/**
* 内部类大展身手 ———— 内部类提供闭包,实现回调接口:
*
* 回调(Callback):
*
* 将一般回调接口命名为 Callback ,
* 回调引用命名为 callbackReference,
* 包含回调引用的方法命名为 f(Callback callbackReference)
*
* 那么,回调机制最一般过程:
* 1)A类实现回调接口 Callback; A类 –> 被调用方
* 2) B类中有回调引用 callbackReference 和 f B类 –> 回调方
* 3) 在某个时刻,B类的回调引用捕捉 A类 对象,
* 即执行语句 f(new A());
* 然后,通过这个回调引用去调用A类的方法,这个被调用的方法就称为 回调方法
*
* 注:你也可以,在A类中,调用B类的 f,
* 调用语句如下: new B().f(A.this);
* 更一般的情况是:A类 中含有 B类 的引用 b ,所以直接 b.f(A.this);
*
* 下面的例子:
* Incrementable –> 回调接口
* increment() –> 回调方法
*/
interface Incrementable{
void increment();
}
//简单地实现接口
class Callee1 implements Incrementable{
private int i = 0;
public void noCallback(){
System.out.println("Callee1: Please don't callback me!!!");
}
@Override
public void increment() {
i++;
System.out.println("Callee1 i = "+i);
}
}
class Callee2{
private int i = 0;
public void noCallback(){
System.out.println("Callee2 : Please don't callback me!!!");
}
public void increment() {
i++;
System.out.println("Callee2 i = "+i);
}
/**
* 这里通过内部类实现回调接口来完成回调机制的好处是:
* 这里,内部类相当于外部类的一个“窗口”,而透过这个“窗口”,
* 你只能看到 外部类 的 increment() 方法,这提供了一种安全保证。
*/
public class Closure implements Incrementable{
@Override
public void increment() {
Callee2.this.increment();
}
}
Incrementable getCallbackReference(){
return new Closure();
}
}
class Caller{
private Incrementable callbackReference; //回调引用
Caller(Incrementable callbackReference) {
this.callbackReference = callbackReference;
}
public Incrementable callbackReference() {
return callbackReference;
}
}
public class Callbacks {
public static void main(String[] args) {
Callee1 c1 = new Callee1();
Callee2 c2 = new Callee2();
//Caller 捕捉 Callee 类的引用
Caller caller1 = new Caller(c1);
Caller caller2 = new Caller(c2.getCallbackReference());
//对于 caller1
caller1.callbackReference().increment(); //这个是允许的
//通过 回调引用 向下转型访问 noCallback()
((Callee1)caller1.callbackReference()).noCallback(); //这个是不允许的,不安全
caller2.callbackReference().increment();
//((Callee2)caller2.callbackReference()).noCallback();
// 错误的转型,内部类基类的引用转型为外部类
//((Callee2.Closure)caller2.callbackReference()).increment();
// 若内部类公有,转型也是多余,只能访问 increment().
}
}
运行结果
错误转型
最后,通过以上例子,可以看出 哪个被调用方(Callee) 传递引用 给 回调方(Caller),回调方就调用 那个 被调用方的 方法,这种“动态调用”,类似于多态,这也就是回调机制的灵活性所在。