点击关注程序员港湾,每天给你一点成长
闭包一直都是Java社区中争论不断的话题,很多语言例如Javascript,RubyPython等都支持闭包这个语言特性,闭包功能强大且灵活,并没有显式地支持它,但其实中也存在着所谓的”闭包”.
闭包
定义一个闭包的要点如下:
一个依赖于外部环境的自由变量的函数.
这个函数能够访问外部环境的.
也就是说,外部环境持有内部函数所依赖的 自由变量 ,由此对内部函数形成了闭包.
自由变量
那么什么是自由变量呢?自由变量 就是在函数自身作用域之外的变量,一个函数f(x)=x+y" tabindex="0" class="MathJax"> f ( x ) = x + y,其中y就是,它并不是这个函数自身的自变量,而是通过外部环境提供的.
下面以Javascript的一个闭包为例:
1
2
3
4
5
function Add ( y ){
returnfunction ( x )
x + y;
}
对于内部函数function(x)来说,.而是函数Add(y)内的参数,所以对内部函数形成了一个闭包.
这个闭包将自由变量y与内部函数绑定在了一起,也就是说,当函数执行完毕后,它不会随着函数调用结束后被回收(不能在栈上分配空间).
varadd_function = Add(5);// 这时y=5,并且与返回的内部函数绑定在了一起
result = add_function(10// x=10,返回最终的结果 10 + 5 = 15
Java中的闭包
Java与又或者其他支持闭包的语言不同,它是一个基于类的面向对象语言,也就是说一个方法所用到的 自由变量 永远都来自于其所在类的实例的.
6
7
class AddUtils
privateinty =;
public int add ( int x)
retrun x + y;
这样一个方法add(x)拥有一个参数x与一个,它的返回值也依赖于这个.想要正常工作的话,就必须依赖于AddUtils类的一个实例,不然它无法知道的值是多少,也就是未与进行绑定.
严格上来说,中的应该为this,这是因为也是通过关键字来访问的.
所以说,在中闭包其实无处不在,只不过我们难以发现而已.但面向对象的语言一般都不把类叫成闭包,这是一种习惯.
中的内部类就是一种典型的闭包结构.
8
9
10
11
12
publicclass Outer
class Inner
x =
public int add ()
内部类通过一个指向外部类的引用来访问外部环境中的,由此形成了一个闭包.
匿名内部类
13
14
15
16
public interface AnonInner ()
int add ()
public AnonInner getAnonInner ( final int x)
final
newAnonInner() {
getAnonInner(x)方法返回了一个匿名内部类AnonInner,匿名内部类不能显式地声明构造函数,也不能对构造函数传参,且返回的是一个接口,但它的add()方法实现中用到了两个(),也就是说外部方法对这个匿名内部类构成了闭包.
但我们发现都被加上了final修饰符,这是因为对闭包支持的不完整导致的.
对于的捕获策略有以下两种:
capture-by-value: 只需要在创建闭包的地方把捕获的值拷贝一份到对象里即可.Java的匿名内部类和Java 8新的lambda表达式都是这样实现的.
capture-by-reference: 把被捕获的局部变量“提升”(hoist)到对象里.C#的匿名函数(匿名委托/lambda表达式)就是这样实现的.
只实现了capture-by-value,但又没有对外说明这一点,为了以后能进一步扩展成支持capture-by-reference留后路,所以干脆就不允许向被捕获的变量赋值,所以这些需要强制加上修饰符(在Jdk8中似乎已经没有这种强制限制了).
作者: SylvanasSun
源自:https://sylvanassun.github.io/2017/07/30/2017-07-30-JavaClosure/
声明:文章著作权归作者所有,如有侵权,请联系小编删除。
感谢 · 转发 欢迎大家留言