https://blog.csdn.net/z69183787/article/details/68490440编程
https://www.zhihu.com/question/21395848跨域
https://www.zhihu.com/question/24084277/answer/110176733闭包
喜欢看生肉的同窗就不用看个人回答了,直接看R大的三篇回答,尤为是第一篇后面的回复部分。编程语言
我只是试着用大白话作个简单的整理,但愿能更容易理解一点。
函数
关于对象与闭包的关系的一个有趣小故事 (这篇的精华在后面的回复,小故事能够跳过)
this
JVM的规范中容许编程语言语义中建立闭包(closure)吗? - RednaxelaFX 的回答.net
为何Java闭包不能经过返回值以外的方式向外传递值? - RednaxelaFX 的回答指针
1. 闭包(Closure)
什么是闭包,大白话不怎么严谨的说就是:
对象
看下面这个Javascript闭包的例子:blog
对内部函数function(x)来说,y就是自由变量,并且function(x)的返回值,依赖于这个外部自由变量
y。而往上推一层,外围Add(y)函数正好就是那个包含自由变量y的环境。并且Javascript的语法允
许内部函数function(x)访问外部函数Add(y)的局部变量。知足这三个条件,因此这个时候,外部函
数Add(y)对内部函数function(x)构成了闭包。
闭包的结构,若是用λ演算表达式来写,就是多参数的Currying技术。
>λx.λy.x+y
但在Java中咱们看不到这样的结构。由于Java主流语法不容许这样的直接的函数套嵌和跨域访问变量。
2. 类和对象
但Java中真的不存在闭包吗?正好相反,Java处处都是闭包,因此反而咱们感受不出来在使用闭
包。由于Java的“对象”其实就是一个闭包。其实不管是闭包也好,对象也好,都是一种数据封装的
手段。看下面这个类
看上去x在函数add()的做用域外面,可是经过Add类实例化的过程,变量”x“和数值”2“之间已经绑
定了,并且和函数add()也已经打包在一块儿。add()函数实际上是透过this关键字来访问对象的成员字
段的。
若是对闭包有疑问,能够看这个更详细的回答:
3. Java内部类是闭包:包含指向外部类的指针
那Java里有没有除了实例对象以外的闭包结构?Java中的内部类就是一个典型的闭包结构。例子以下,
下图画的就是上面代码的结构。内部类(Inner Class)经过包含一个指向外部类的引用,作到自
由访问外部环境类的全部字段,变相把环境中的自由变量封装到函数里,造成一个闭包。
4. 别扭的匿名内部类
但Java匿名内部类就作得比较尴尬。下面这个例子中,getAnnoInner负责返回一个匿名内部类的引用。
匿名内部类由于是匿名,因此不能显式地声明构造函数,也不能往构造函数里传参数。不但返回的只是个叫AnnoInner的接口,并且尚未和它外围环境getAnnoInner()方法的局部变量x和y构成任何类的结构。但它的addXYZ()函数却直接使用了x和y这两个自由变量来计算结果。这就说明,外部方法getAnnoInner()事实上已经对内部类AnnoInner构成了一个闭包。
但这里别扭的地方是这两个x和y都必须用final修饰,不能够修改。若是用一个changeY()函数试图修改外部getAnnoInner()函数的成员变量y,编译器通不过,
error: cannot assign a value to final variable y
这是为何呢?由于这里Java编译器支持了闭包,但支持地不完整。说支持了闭包,是由于编译器编译的时候其实悄悄对函数作了手脚,偷偷把外部环境方法的x和y局部变量,拷贝了一份到匿名内部类里。以下面的代码所示。
因此用R大回答里的原话说就是:
Java编译器实现的只是capture-by-value,并无实现capture-by-reference。
而只有后者才能保持匿名内部类和外部环境局部变量保持同步。
但Java又不愿明说,只能粗暴地一刀切,就说既然内外不能同步,那就不准你们改外围的局部变量。
5. 其余和匿名内部类类似的结构
《Think in Java》书里,只点出了匿名内部类来自外部闭包环境的自由变量必须是final的。但实际上,其余几种不太经常使用的内部类形式,也都有这个特性。
好比在外部类成员方法内部的内部类。
好比在一个代码块block里的内部类。