内部类的闭包与回调

来源:互联网 发布:宇宙数控系统编程 编辑:程序博客网 时间:2024/06/05 10:36
         闭包(Closure)是一种能被调用对象,它保存了创建它的作用域的信息。
        Java并不能显式地支持闭包,但对于非静态内部类而言,它不仅记录了其外部类的详细信息,还保留了一个创建非静态内部类对象的引用,并且可以直接调用外部类的private成员,因此可以把非静态内部类当成面向对象领域的闭包。

        通过这种仿闭包的非静态内部类,可以很方便地实现回调功能,回调就是某个方法一旦获得了内部类对象的引用后,就可以在合适时候反过来调用外部类的方法。所谓回调,就是允许客户类通过内部类引用来调用其外部类的方法,这是一种非常灵活的功能。

interface Incrementable{    void increment();}class Callee1 implements Incrementable// 实现类Callee1{    private int i = 0;    @Override    public void increment()    {        i++;        System.out.println("Callee1 increment()被调用" + i + "次");    }}class MyIncrement{    public void increment()    {        System.out.println("MyIncrement increment()被调用饿啦");    }    static void f(MyIncrement mi)    {        mi.increment();    }}class Callee2 extends MyIncrement// 重新定义的子类{    private int i = 0;    public void increment()    {        super.increment();        i++;        System.out.println("Callee2 increment()被调用" + i + "次");    }    private class Closure implements Incrementable// 内部类实现类Closure    {        @Override        public void increment()        {            Callee2.this.increment();        }    }    Incrementable getCallbackReference()// 返回接口引用    {        return new Closure();    }}/** * @author linlin 回调类与回调方法 */class Caller{    private Incrementable callbackReference;    public Caller(Incrementable callbackReference)    {        this.callbackReference = callbackReference;    }    void go()    {        this.callbackReference.increment();    }}public class CallBacks{    public static void main(String[] args)    {        Callee1 callee1 = new Callee1();        Caller caller1 = new Caller(callee1);        caller1.go();        caller1.go();                Callee2 callee2 = new Callee2();        MyIncrement.f(callee2);        Caller caller2 = new Caller(callee2.getCallbackReference());        caller2.go();        caller2.go();    }}
输出结果如下:
Callee1 increment()被调用1次
Callee1 increment()被调用2次

MyIncrement increment()被调用饿啦
Callee2 increment()被调用1次
MyIncrement increment()被调用饿啦
Callee2 increment()被调用2次
MyIncrement increment()被调用饿啦
Callee2 increment()被调用3次


       这个例子展示了外围类实现一个接口与内部类实现接口的区别。就代码而言,Callee1是简单的解决方式。Callee2继承自MyIncrement,后者已经有了一个不同的increment()方法,并且与Incrementable接口期望的increment()方法完全不相关。所以如果Callee2继承了MyIncrement,就不能为了Incrementable的用途而覆盖Increment()方法,于是只能使用内部类独立地实现Incrementable。还要注意,当创建一个内部类时,并没有在外围类的接口中添加东西,也没有修改外围类的接口。

      注意,在Callee2中除了getCallbackReference()以外,其他成员都是private的。要想建立与外部世界的任何连接,interface Incrementable都是必须的。在这里可以看到,interface是如何允许接口与接口的实现完全独立地。

      内部类Closure实现了Incrementable,以提供一个返回Callee2的"钩子"(hook)--而且是一个安全的钩子。无论谁获得此Incrementale的引用,都只能调用increment(),除此之外没有其他功能(不像指针那样,允许你做很多事情)。

      Caller的构造器需要一个Incrementable的引用作为参数(虽然可以在任意时刻捕获回调引用),然后在以后的某个时刻,Caller对象可以使用此引用回调Callee类。

阅读全文
0 0
原创粉丝点击