Java—内部类(二)—实现闭包与回调

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yuwenhao07/article/details/53607117

前言:

Java的闭包与回调我也是第二次接触这个概念,之前在自学Android的时候绘制View很多地方都用到了监听器回调,一直不是很明白,现在回头巩固Java的基础总算的弄明白,尽量用我自己理解的语言来和大家分享,希望对不懂的朋友可以有一定的帮助,大神也可以给我一点指点。

概念:

我觉得在理解一个事物之前,需要对这个事物在我们的大脑里有一个初步的概念,然后再对这个概念补充上细节,这是我在理解一些陌生事物的时候的一个方法,也可以说是类比理解法吧。先说闭包~

一.闭包
闭包,故名思意就是,把一个包关起来,那么对于Java来说,这个包就是类了,因为在java中任何事物都是类,都是对象。那么闭包,直接理解上就是把一个类封装起来(封装就是包装差不多的意思)。然后结合一下,闭包内容放在内部类中,所以闭包就是用一个类把另一个类包装起来,说起来这和内部类没有什么不同点啊,为啥要专门用一个词来表述它呢?因为这个闭包还有很多其他的作用。而且其构造要比内部类复杂一点,先说说它的作用,作用有二~
1. 闭包能够保护内部类里面的变量安全,不会被外部访问
2. 闭包能够维持一个变量一直存活在内存中,不被CG(垃圾回收机制)回收掉
在构造上,内部类需要提供一个给外部调用它的接口,这样才能在维持住内部类的同时,因为内部类携带了外部类的信息,所以外部类也得以存活。

二.回调
回调直接理解就是回头调用,先将相关的方法实现好,但是并不由我来决定什么时候来调用它,而是等到一个时候,程序自己回头调用这个方法,而实现回调机制,这可以说是一种设计模式,而不仅仅是一个语言上的特性。与回调相关的概念还有同步调用,与异步调用,同步调用即单向调用,调用方等待对方执行完成后才返回。异步调用则类似消息机制,等待收到一定的消息后执行某些操作,回调与异步调用有一些共同之处,现在理解的还不是很清楚,先埋下一坑,以后清楚了在补一篇。

实例:

接下来就直接上代码分析,让大家补充一些细节上的理解,来清楚整个过程,整个过程相当于我的口述,如有不对的地方,希望大家指出:

interface Incrementable{
    void increment();
}

class Callee1 implements Incrementable{
    private int i = 0;
    public void increment(){
        i++;
        System.out.println(i);
    }
}

class MyIncrementable {
    public void increment(){ System.out.println("Other Operarion"); }
    static void f(MyIncrementable mi){ mi.increment(); }
}

class Callee2 extends MyIncrementable{
    private int i = 0;
    public void increment(){
        super.increment();
        i++;
        System.out.println(i);
    }
    private class Closure implements Incrementable{
        public void increment(){
            Callee2.this.increment();
        }
    }
    Incrementable getCallbackReference(){
        return new Closure();
    }
}

class Caller{
    private Incrementable callbackReference;
    Caller(Incrementable cbn){ callbackReference = cbn; }
    void go(){ callbackReference.increment(); }
}

public class Callbacks {
    public static void main(String[] args){
        Callee1 c1 = new Callee1();
        Callee2 c2 = new Callee2();
        MyIncrementable.f(c2);
        Caller caller1 = new Caller(c1);
        Caller caller2 = new Caller(c2.getCallbackReference());
        caller1.go();
        caller1.go();
        caller2.go();
        caller2.go();
    }

}

这个是java编程思想上很经典的一个例子。输出是这样的:

Other Operarion
1
1
2
Other Operarion
2
Other Operarion
3

希望大家首先自己通读一下代码,然后理解一下程序输出结果为什么是这样的,这样有助于我们去理解之前所说的闭包与回调机制。

这里我默认大家看完了,我来说一下我的理解:
首先Callee1是一个简单的实现了接口Incrementable与相关方法,在这里起到一个对比的作用而已。然后实现了一个MyIncrement类同样实现了一个increment()方法但是这个与接口中的increment()没有任何关系,因为这个类自己实现的,并没有实现这个接口,而静态方法f()也只是为了测试一下increment()方法。而Callee2继承自这个类。这里就是重点了。同样写了一个increment()方法,覆盖了父类方法,但是中间还是调用了父类方法。接下里是一个内部类也就是闭包的具体实现了。内部类实现了接口Incrementable并且直接调用外部类的方法作为具体的实现。内部类实现Increment able接口很关键,这样就给外部留下了一个通道,能够接受这个内部类。最后Callee2的后面留下了一个钩子,即getCallbackReference()方法,它返回一个内部类的对象,实现了内部与外部的链接,同时有保证了内部类的安全,因为只有Callee2的对象可以访问与调用这个内部类的方法,而其他的类都无权访问,即使是基类接口对象。而后面的Caller类起到的是一个唤醒作用,通过接受不同的接口对象,实现不同的操作,但还有一个作用是等待接受一个内部类对象,来产生回调。现在大家再回头看一下输出就能够明白了。

假装你回头看了,在main()方法中,首先是创建对象与声明,然后是调用了一个MyIncrement的静态方法,传入的是一个Callee2对象,此时无法触发回调,所以只是正常的输出,然后,才Caller2的初始化时传入的是一个Closure对象从而产生了回掉。

以上就是java的闭包与回调机制,结合后面的内容会有更多意想不到的作用~

展开阅读全文

没有更多推荐了,返回首页