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

概念:  

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

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

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

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

interface Incrementable{
    void increment();
}

class Callee1 implements Incrementable{
    private int i = 0;
    @Override
    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;
    @Override
    public void increment(){
        super.increment();
        i++;
        System.out.println(i);
    }
    private class Closure implements Incrementable{
        @Override
        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的闭包与回调机制,结合后面的内容会有更多意想不到的作用~
 

 

========================================================

附:

interface OrderResult {
    /**
     * 订购货物的状态
     *
     * @param state
     * @return
     */
    //参数可以不用, 用不用按照自己的实际需求决定
    public String getOrderResult(String state);
}

class Store {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    Store(String name) {
        this.name = name;
    }

    /*回调函数, 将结构传给那个我们不能直接调用的方法, 然后获取结果*/
    public String returnOrderGoodsInfo(OrderResult order) {
        String[] s = {"订购中...", "订购失败", "即将发货!", "运输途中...", "已在投递"};
        Random random = new Random();
        int temp = random.nextInt(5);
        String s1 = s[temp];
        return order.getOrderResult(s1);
    }
}

//同步回调
class SyncBuyer implements OrderResult {
    private Store store;//商店
    private String buyerName;//购物者名
    private String goodsName;//所购商品名

    public Store getStore() {
        return store;
    }

    public void setStore(Store store) {
        this.store = store;
    }

    public String getBuyerName() {
        return buyerName;
    }

    public void setBuyerName(String buyerName) {
        this.buyerName = buyerName;
    }

    public String getGoodsName() {
        return goodsName;
    }

    public void setGoodsName(String goodsName) {
        this.goodsName = goodsName;
    }

    SyncBuyer(Store store, String buyerName, String goodsName) {
        this.store = store;
        this.buyerName = buyerName;
        this.goodsName = goodsName;
    }

    /*调用从商店返回订购物品的信息*/
    public String orderGoods() {
        String goodsState = store.returnOrderGoodsInfo(this);
        System.out.println(goodsState);
        myFeeling();// 测试同步还是异步, 同步需要等待, 异步无需等待
        return goodsState;

    }

    public void myFeeling() {
        String[] s = {"有点小激动", "很期待!", "希望是个好货!"};
        Random random = new Random();
        int temp = random.nextInt(3);
        System.out.println("我是" + this.getBuyerName() + ", 我现在的感觉: " + s[temp]);
    }

    /*被回调的方法, 我们自己不去调用, 这个方法给出的结果, 是其他接口或者程序给我们的, 我们自己无法产生*/
    @Override
    public String getOrderResult(String state) {
        return "在" + this.getStore().getName() + "商店订购的" + this.getGoodsName() + "玩具, 目前的预订状态是: " + state;
    }
}

//异步回调
class NoSyncBuyer implements OrderResult {
    private Store store;//商店
    private String buyerName;//购物者名
    private String goodsName;//所购商品名

    public Store getStore() {
        return store;
    }

    public void setStore(Store store) {
        this.store = store;
    }

    public String getBuyerName() {
        return buyerName;
    }

    public void setBuyerName(String buyerName) {
        this.buyerName = buyerName;
    }

    public String getGoodsName() {
        return goodsName;
    }

    public void setGoodsName(String goodsName) {
        this.goodsName = goodsName;
    }

    NoSyncBuyer(Store store, String buyerName, String goodsName) {
        this.store = store;
        this.buyerName = buyerName;
        this.goodsName = goodsName;
    }

    /*调用从商店返回订购物品的信息*/
    public String orderGoods() {
        String goodsState = "--";
        MyRunnable mr = new MyRunnable();
        Thread t = new Thread(mr);
        t.start();
        System.out.println(goodsState);
        goodsState = mr.getResult();// 得到返回值
        myFeeling();// 用来测试异步是不是还是按顺序的执行
        {//等待异步完成(测试)
            for (int i = 0; i < 20; i++) {
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                goodsState = mr.getResult();
                if (goodsState != null) {
                    return goodsState;
                }
            }
        }
        return goodsState;
    }

    public void myFeeling() {
        String[] s = {"有点小激动", "很期待!", "希望是个好货!"};
        Random random = new Random();
        int temp = random.nextInt(3);
        System.out.println("我是" + this.getBuyerName() + ", 我现在的感觉: " + s[temp]);
    }

    /*被回调的方法, 我们自己不去调用, 这个方法给出的结果, 是其他接口或者程序给我们的, 我们自己无法产生*/
    @Override
    public String getOrderResult(String state) {
        return "在" + this.getStore().getName() + "商店订购的" + this.getGoodsName() + "玩具, 目前的预订状态是: " + state;
    }

    // 开启另一个线程, 但是没有返回值, 怎么回事
    // 调试的时候, 等待一会儿, 还是可以取到值, 但不是立即取到, 在print显示的时候, 却是null, 需要注意?
    private class MyRunnable implements Runnable {
        private String result;

        public String getResult() {
            return result;
        }

        public void setResult(String result) {
            this.result = result;
        }

        @Override
        public void run() {
            try {
                Thread.sleep(10000);
                result = store.returnOrderGoodsInfo(NoSyncBuyer.this);// 匿名函数的时候, 无法return 返回值
            } catch (InterruptedException e) {
                throw new RuntimeException("出大事了, 异步回调有问题了");
            }
        }
    }
}

class TestCallback {
    public static void main(String[] args) {
        Store wallMart = new Store("沙中路沃尔玛");
        SyncBuyer syncBuyer = new SyncBuyer(wallMart, "小明", "超能铁扇公主");
        System.out.println(syncBuyer.orderGoods());


        System.out.println("\n");
        Store lawson = new Store("沙中路罗森便利店");
        NoSyncBuyer noSyncBuyer = new NoSyncBuyer(lawson, "cherry", "变形金刚");
        System.out.println(noSyncBuyer.orderGoods());
    }
}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值