李林超博客
首页
归档
留言
友链
动态
关于
归档
留言
友链
动态
关于
首页
Java
正文
内部类之--闭包与回调
Leefs
2019-11-24 AM
3239℃
1条
# 内部类之--闭包与回调 ### 前言 之前在学习Java基础的时候对闭包和回调有一些简单了解,但是现在对这个概念已经很模糊了,所以现在借此机会进行一下回顾,记录一下 ### 一、概念 **闭包:**闭包,故名思意就是,把一个包关起来,那么对于Java来说,这个包就是类了,因为在java中任何事物都是类,都是对象。那么闭包,直接理解上就是**把一个类封装起来**(封装就是包装差不多的意思)。然后结合一下,闭包内容放在内部类中,所以**闭包就是用一个类把另一个类包装起来**,说起来这和内部类没有什么不同点啊,为啥要专门用一个词来表述它呢?因为这个闭包还有很多其他的作用。而且其构造要比内部类复杂一点: > 1. 1.闭包能够保护内部类里面的变量安全,不被外部访问 > 2. 2.闭包能够维持一个变量一直存活在内存中,不被CG(垃圾回收机制)回收掉 在构造上,内部类需要提供一个给外部调用它的接口, 这样才能维持住内部类 ,同时因为内部类携带了外部类的信息,所以外部类也得以存活。 **回调**:回调直接理解就是回头调用,先将相关的方法实现好,但是并不由我来决定什么时候调用它,而是等到一个时候,程序自己回头调用这个方法,而实现回调机制,这可以说是一种设计模式, 而不仅仅是一个语言上的特性。与回调相关的概念还有同步调用,与异步调用,同步调用即单向调用,调用方等待对方执行完成后才返回。异步调用则类似消息机制,等待收到一定的消息后执行某些操作, > 书中概念 闭包:是一个可调用的对象,它记录了一些信息,这些信息来自于创建它的作用域。通过这个定义,可以看出内部类是面向对象的闭包,因为它不仅包含外围类对象(创建内部类的作用域)的信息,还自动拥有一个指向此外围类对象的引用,在此作用域内,内部类有权操作所有的成员,包括private成员。 Java最引人争议的问题之一就是,人们认为Java应该包含某种类似指针的机制,以允许回调。通过回调,对象能够携带一些信息,这些信息允许它在稍后的某个时刻调用初始的对象。稍后将会看到这是一个非常有用的概念。如果回调是通过指针实现的,那么就只能寄希望于程序员不会误用该指针。然而,读者应该已经了解到,Java更小心仔细,所以没有在语言中包括指针。 通过内部类提供闭包的功能是优良的解决方案,它比指针更灵活、更安全。 见下例: ```java interface Incrementable{ void increment(); } class Callee1 implements Incrementable{ public Callee1(){ System.out.println("hello world"); } 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 hello world Other Operarion 1 101 102 Other Operarion 2 Other Operarion 3 ``` > 代码分析 > 1. 1.接口`Incrementable` > 2. 2.类`Callee1`继承接口`Incrementable`,并实现接口中的increment()方法 > 3. 3.类`MyIncrementable`中有公共方法increment()和静态方法f(),f()调用了公共方法中的`incerment()`方法 > 4. 4.类`Callee2`继承`MyIncrementable`类 > 5. 5.在类`Callee2`中重写了`MyIncrementable`类的increment()方法,同时调用了父类的increment()方法 > 6. 6.内部类`Closure`继承`Incrementable`接口,在实现的increment()方法中,调用了外部类的increment()方法 > 7. 7.`Callee2`类中的方法`getCallbackReference`()返回一个Closure对象的回调 大家可以在此基础上Debug一下,观察一下整个代码的执行流程,小编在这就不过多叙述了。 **总结** 首先`Callee1`是一个简单的实现了接口`Incrementable`与相关方法,在这里起到一个对比的作用而已。然后实现了一个`MyIncrement`类同样实现了一个`increment()`方法但是这个与接口中的`increment()`没有任何关系,因为这个类自己实现的,并没有实现这个接口,而静态方法f()也只是为了测试一下`increment()`方法。而`Callee2`继承自这个类。这里就是重点了。**同样写了一个`increment()`方法,覆盖了父类方法,但是中间还是调用了父类方法。接下里是一个内部类也就是闭包的具体实现了**。**内部类实现了接口`Incrementable`并且直接调用外部类的方法作为具体的实现。内部类实现Increment able接口很关键,这样就给外部留下了一个通道,能够接受这个内部类。**最后`Callee2`的后面留下了一个钩子,即`getCallbackReference()`方法,它返回一个内部类的对象,实现了内部与外部的链接,同时有保证了内部类的安全,因为只有`Callee2`的对象可以访问与调用这个内部类的方法,而其他的类都无权访问,即使是基类接口对象。而后面的Caller类起到的是一个唤醒作用,通过接受不同的接口对象,实现不同的操作,但还有一个作用是等待接受一个内部类对象,来产生回调。现在大家再回头看一下输出就能够明白了。 回调的价值在于它的灵活性--可以在运行时动态地决定需要调用什么方法。 附:[参考文章链接](https://blog.csdn.net/yuwenhao07/article/details/53607117)
标签:
Java
,
Java编程思想
,
JavaSE
非特殊说明,本博所有文章均为博主原创。
如若转载,请注明出处:
https://www.lilinchao.com/archives/220.html
上一篇
为什么需要内部类
下一篇
持有对象--泛型和类型安全的容器
取消回复
评论啦~
提交评论
唉呀 ~ 仅有一条评论
孤独这杯酒
垃圾回收不是gc吗
回复
2019-11-26 19:59
栏目分类
随笔
2
Java
326
大数据
229
工具
31
其它
25
GO
47
标签云
二叉树
栈
Kafka
序列化和反序列化
Eclipse
Shiro
FileBeat
线程池
稀疏数组
微服务
并发编程
Stream流
Zookeeper
Hbase
锁
容器深入研究
DataX
Azkaban
前端
RSA加解密
Yarn
Nacos
HDFS
链表
Scala
nginx
Python
高并发
Thymeleaf
Java
友情链接
申请
范明明
庄严博客
Mx
陶小桃Blog
虫洞
垃圾回收不是gc吗