李林超博客
首页
归档
留言
友链
动态
关于
归档
留言
友链
动态
关于
首页
Java
正文
内部类之--闭包与回调
Leefs
2019-11-24 AM
4107℃
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://lilinchao.com/archives/220.html
上一篇
为什么需要内部类
下一篇
持有对象--泛型和类型安全的容器
评论已关闭
栏目分类
随笔
2
Java
326
大数据
229
工具
31
其它
25
GO
47
NLP
4
标签云
Hive
Http
工具
JVM
Python
SpringCloudAlibaba
Java工具类
序列化和反序列化
正则表达式
数学
DataX
RSA加解密
并发线程
Spark Streaming
Typora
Redis
Scala
Linux
VUE
SQL练习题
Golang基础
Flume
NIO
队列
并发编程
Quartz
线程池
JavaWeb
二叉树
Filter
友情链接
申请
范明明
庄严博客
Mx
陶小桃Blog
虫洞
评论已关闭