解释下程序:
interface Incrementable {
void increment();
}
// Very simple to just implement the interface:
class Callee1 implements Incrementable {
private int i = 0;
public void increment() {
i++;
System.out.println(i);
}
}
class MyIncrement {
void increment() {
System.out.println("Other operation");
}
static void f(MyIncrement mi) { mi.increment(); }
}
// If your class must implement increment() in
// some other way, you must use an inner class:
class Callee2 extends MyIncrement {
private int i = 0;
private void incr() {
i++;
System.out.println(i);
}
private class Closure implements Incrementable {
public void increment() { incr(); }
}
Incrementable getCallbackReference() {
return new Closure();
}
}
class Caller {
private Incrementable callbackReference;
Caller(Incrementable cbh) { callbackReference = cbh; }
void go() { callbackReference.increment(); }
}
public class Callbacks {
private static Test monitor = new Test();
public static void main(String[] args) {
Callee1 c1 = new Callee1();
Callee2 c2 = new Callee2();
MyIncrement.f(c2);
Caller caller1 = new Caller(c1);
Caller caller2 = new Caller(c2.getCallbackReference());
caller1.go();
caller1.go();
caller2.go();
caller2.go();
}
} ///:~
结果是:
Other operation
1
2
1
2
我的理解:
首先想有必要解释一下内部类和回调.知其然还要知其所以然,所以我会说一下为什么要使用内部类和回调,他们能有什么好处和完成什么工作.
内部类就是声明在一个类里面的类,相对于内部类的我们称外部类,内部类包括有实例内部类和静态内部类,声明在方法中的我们称局部内部类,在这里我就只介绍实例内部类,其他的内部类的用法和规则你自己可以参考一下<<JAVA面向对象编程>>这本书
我们用实例内部类有两个好处,其一可以简化编程,而且便于我们封装细节,这个作用了解了可以用来应付以后面试时遇到的面试老师,呵呵.其二,实例内部类可以随意访问外部类的所有成员变量,这也就是内部类最强大的地方.注意我这里说的时实例内部类,其他的内部类(如静态内部类)都有自己不同的访问规则,要区别对待哦.
好了介绍了内部类,我再说说回调吧,说回调之前,我喜欢用一个我自己想的比喻来形容,可能比较好懂些.比如我(子类)现在又想养猫(接口的方法)又想养鱼(父类的方法)在我的家里,我喜欢鱼,觉得鱼可能对我的家以后的装饰更有用于是我先养了鱼(继承了父类的方法),但是我还是想养猫啊,而猫和鱼又不能同时一起养(父类的方法与继承的接口需要实现的方法同名,不能同时存在一个相同的名字空间),怎么办呢?于是我想了好办法,叫来我可爱的老婆(内部类),呵呵,我让我亲爱的老婆去养猫(继承接口实现其方法),但是我老婆很懒,她才不愿意去给猫买吃的了(内部类不具体的实现接口的方法),其实每次都还是我把猫粮买回来(外部类提供方法的实现)交给她就行了(内部类调用外部类实现的方法去实现接口的方法).这样当我想跟我的猫玩耍的时候(使用实现接口的方法)我就会找我老婆,让她给我把猫领出来玩.这样不就完成了我的目的了吗,当然为了每次我有途径联系到我的老婆(内部类)我自己必须给她配个手机(回调方法,返回内部类实例),这样我才能随叫随到,随到随用了对不~呵呵,提供方法返回内部类实例来执行相应接口的方法,其实这就是所谓的回调了
最后说下回调的好处:回调实质上是指一个类尽管实际上实现了某种功能但是没有直接提供相应的接口,客户类可以通过这个类的内部类的接口来获得这种功能,这个内部类本身不提供真正的实现,仅仅调用外部类的实现.可见回调可以充分发挥了内部类所具有的访问外部类的实现细节的优势.
解释完上面这些,你是否对程序有点理解了呢?
没错,我们接下来分析程序:
首先一个接口:interface Incrementable {
void increment();
}
一个实现类,实现了Incrementable 接口:
class Callee1 implements Incrementable {
private int i = 0;
public void increment() {
i++;
System.out.println(i);
}
}
然后我们看main方法
第一句Callee1 c1 = new Callee1();
然后是一个"情妇"注意不是我的老婆哦~呵呵,我的情妇专门负责返回一个Incrementable类型的引用变量,
当我这样Caller caller1 = new Caller(c1);的时候,实际上是让这个引用变量引用一个Callee1类型的实例,所以用
caller1.go();方法时虽然caller1声明的是Caller,但是由于java的多态机制,实际上JVM会调用Callee1类的go()方法,所以你明白了吗结果第一个1,2就是这样来的.
再回到main方法
先看这个:
class Callee2 extends MyIncrement {
private int i = 0;
private void incr() {
i++;
System.out.println(i);
}
private class Closure implements Incrementable {
public void increment() { incr(); }
}
Incrementable getCallbackReference() {
return new Closure();
}
}
这个类就是一个外部类继承父类方法,内部类实现接口方法而调用外部类的实现的典型例子了,然后外部类会提供一个getCallbackReference()方法返回内部类实例.(Closure就是内部类了^_^)
注意:Callee2 c2 = new Callee2();
MyIncrement.f(c2);
Caller caller2 = new Caller(c2.getCallbackReference());
这里用了什么?没错就是用了回调了啦c2.getCallbackReference()获取了Incrementable的实现类让上面我提到过的Caller类型的引用变量指向他,然后在调用其go()方法,所以就出来结果后面两个1,2了咯.
纵观程序,其实也就是用两种方法来获得两种实例,然后调用实例的go()方法而已啦,而且这两个实例所在的类对其go()方法叶实现的不一样,一个是实现接口的方法,一个是自调用自己的方法,这在java里面又涉及两个经典的讨论--组合模式与继承实现模式,对于这个我还是建议楼主去看一下书,我就不多介绍这两种模式的利弊了,要不然又是一篇论文了,哈哈.
好了,就说这么多不知道楼主懂了多少,不过没关系,现在不知道不代表你将来不知道,只要你以后多看看有关jvm底层的书籍,你的很多疑惑将一下子豁然开朗了,呵呵,fighting!
一切源于技术,一切源于开放~enjoying!