什么是接口回调,接口回调与向上转型的区别,回调函数的理解

来源:互联网 发布:淘宝发物流怎么填单号 编辑:程序博客网 时间:2024/06/05 19:37

什么是接口回调?
1.接口回调是什么[2]?
接口回调是指:可以把使用某一接口的类创建的对象的引用赋给该接口声明的接口变量,那么该接口变量就可以调用被类实现的接口的方法。实际上,当接口变量调用被类实现的接口中的方法时,就是通知相应的对象调用接口的方法,这一过程称为对象功能的接口回调。看下面示例。
interface People{
void peopleList();
}
class Student implements People{
public void peopleList(){
System.out.println(“I’m a student.”);
}
}
class Teacher implements People{
public void peopleList(){
System.out.println(“I’m a teacher.”);
}
}
public class Example{
public static void main(String args[]){
People a; //声明接口变量
a=new Student(); //实例化,接口变量中存放对象的引用
a.peopleList(); //接口回调
a=new Teacher(); //实例化,接口变量中存放对象的引用
a.peopleList(); //接口回调
}
}
结果:
I’m a student.
I’m a teacher.
再来看看向上转型(upcasting)的概念。

2.什么是向上转型[1]?

Shape s=new Circle();
这里,创建了一个Circle对象,并把得到的引用立即赋值给Shape。通过继承,Circle就是一种Shape。
假设你调用基类方法(它已在导出类中被覆盖):
s.draw();
由于后期绑定(多态),将会正确调用Circle.draw()方法。

3.向上转型与接口回调的区别
看似向上转型和接口回调是一回事。看下面两句话,均出自Thinking in Java。
使用接口的核心原因:为了能够向上转型为多个基类型[1]。即利用接口的多实现,可向上转型为多个接口基类型(具体见《抽象与接口》章节6)。
从实现了某接口的对象,得到对此接口的引用,与向上转型为这个对象的基类,实质上效果是一样的。(此句摘自Thinking in Java 3rd 接口与内部类一章)
所以,我认为,这两个概念是从两个方面来解释一个行为。接口回调的概念,强调使用接口来实现回调对象方法使用权的功能(下一章节详细分析)。而向上转型则牵涉到多态和运行期绑定的范畴。

4.用 Java 接口实现回调函数的等价功能
熟悉 MS-Windows 和 X Window System 事件驱动编程模型的开发人员,习惯于传递在某种事件发生时调用(即“回调”)的函数指针。Java 的面向对象模型目前并不支持方法指针,Java 的接口支持提供了一种获得回调的等价功能的机制。其技巧就是:定义一个简单接口,并在该接口中声明我们要调用的方法。
假定我们希望在某个事件发生时得到通知。我们可以定义一个接口:
InterestingEvent.java
package org.zj.sample;
public interface InterestingEvent {
public void interestingEvent ();
}
这使得我们可以控制实现该接口的类的任何对象。因此,我们不必关心任何外部类型信息。
发出事件信号的类必须等待实现了 InterestingEvent 接口的对象,并在适当时候调用 interestingEvent() 方法。
EventNotifier.java
package org.zj.sample;
public class EventNotifier {
private InterestingEvent ie;
private boolean somethingHappened;

public EventNotifier(InterestingEvent event) {     ie = event; // 保存事件对象以备后用。     somethingHappened = false; // 还没有要报告的事件。}public void doWork() {     if (somethingHappened) { // 检查设置的谓词。       ie.interestingEvent();// 通过调用接口的这个方法发出事件信号。     }}public void setHappened(){//设置谓词。     somethingHappened=true;}

}
在上例中,使用 somethingHappened 谓词来跟踪是否应触发事件。希望接收事件通知的代码必须实现 InterestingEvent 接口,并将自身引用传递给事件通知程序。
CallMe.java
package org.zj.sample;
public class CallMe implements InterestingEvent {
@SuppressWarnings(“unused”)
private EventNotifier en;

public CallMe() {     // 注意 EventNotifier (InterestingEvent event),应该传递一个接口类型。     // 而下面将this,即实现了InterestingEvent接口的CallMe实例传递给

//EventNotifier。也就是所谓的接口回调了。
en = new EventNotifier(this); // 创建事件通知程序,并将自身引用传递给它。
}

// 为事件定义实际的处理程序。public void interestingEvent() {          System.out.println("Call me Hello.");}

}
下面写个测试类。
Test.java
package org.zj.sample;
public class Test {
public static void main(String[] args) {
EventNotifier en=new EventNotifier(new CallMe());
en.setHappened();
en.doWork();
}
}

结果:
Call me Hello.

5.参考资料

Java回调函数的理解
http://blog.csdn.net/fengyifei11228/article/details/5729445
所谓回调,就是客户程序C调用服务程序S中的某个函数A,然后S又在某个时候反过来调用C中的某个函数B,对于C来说,这个B便叫做回调函数。例如Win32下的窗口过程函数就是一个典型的回调函数。一般说来,C不会自己调用B,C提供B的目的就是让S来调用它,而且是C不得不提供。由于S并不知道C提供的B姓甚名谁,所以S会约定B的接口规范(函数原型),然后由C提前通过S的一个函数R告诉S自己将要使用B函数,这个过程称为回调函数的注册,R称为注册函数。Web Service以及Java的RMI都用到回调机制,可以访问远程服务器程序。

下面举个通俗的例子:某天,我打电话向你请教问题,当然是个难题,^_^,你一时想不出解决方法,我又不能拿着电话在那里傻等,于是我们约定:等你想出办法后打手机通知我,这样,我就挂掉电话办其它事情去了。过了XX分钟,我的手机响了,你兴高采烈的说问题已经搞定,应该如此这般处理。故事到此结束。这个例子说明了“异步+回调”的编程模式。其中,你后来打手机告诉我结果便是一个“回调”过程;我的手机号码必须在以前告诉你,这便是注册回调函数;我的手机号码应该有效并且手机能够接收到你的呼叫,这是回调函数必须符合接口规范。通过上面个人感觉到回调更多的应用就是结合异步。比如:Ajax中js通过组件和服务器的异步通信。

例:
程序员A写了一段程序(程序a),其中预留有回调函数接口,并封装好了该程序。程序员B要让a调用自己的程序b中的一个方法,于是,他通过a中的接口回调自己b中的方法。目的达到。在C/C++中,要用回调函数,被掉函数需要告诉调用者自己的指针地址,但在JAVA中没有指针,怎么办?我们可以通过接口(interface)来实现定义回调函数。
假设我是程序员A,以下是我的程序a:

public class Caller
{
public MyCallInterface mc;

public void setCallfuc(MyCallInterface mc)  {     this.mc= mc;  }  public void call(){     this.mc.method();  }  

}

 我还需要定义一个接口,以便程序员B根据我的定义编写程序实现接口。

public interface MyCallInterface
{
public void method();

}

 于是,程序员B只需要实现这个接口就能达到回调的目的了:

public class B implements MyCallInterface
{
public void method()
{
System.out.println(“回调”);
}

public static void main(String args[])  {     Caller call = new Caller();     call.setCallfuc(new B());     call.call();  }  

}

原创粉丝点击