- lamda表达式实际上一个匿名内部类
- 所以我们的问题可以转向这两个问题:
- 为什么匿名内部类调用外部引用的时候,外部引用需要用final修饰?
- lamda如果才能修改外部引用变量?
1. 为什么匿名内部类调用外部引用的时候,外部引用需要用final修饰?
- 我们在内部类中调用外部的自由变量,即使该变量没有显式的声明final,但是在编译器解析的时候也被定义成一个final变量
- 这里java内部类引用外部变量近似闭包的概念。我们先来了解一下js中满足闭包的条件:
- 一个依赖于外部环境自由变量的函数
- 这个函数能够访问外部环境里的自由变量
- 闭包常见使用场景
- 回调函数
- 匿名函数
- 在闭包中访问外部自由变量访问的是自由变量的哪个值呢?
- js中通常我们要解决闭包导致对象不正确问题,常用的有四个解决方案:
- func.call(obj, 20, 30)
- func.apply(obj, [20,30])
- const func1 = func.bind(obj,20,30)
- 在闭包外方法中手动指定 let self = this
- 说到闭包,绕不开this指向问题,this应该指向的是运行时的对象,简单总结this指向三种情况:
- obj.func() -> this指向
.
前面调用的对象,此时指向obj
- new Fun() -> this指向new出来的对象
- 函数自调、匿名函数和回调函数 -> this指向的是window
- java对闭包的处理
- 如函数在使用类的全局变量的时候
- 全局变量实际是类的一个属性,用this指向,可所以修改
- 但是在处理匿名内部类的时候,在不同的类中无法用this指向,这时java的做法是:
- 将自由变量拷贝一个副本带给匿名内部类,供内部类使用。
- 类似于值传递而非引用传递
2. lamda如果才能修改外部引用变量?
- 数组
- 全局变量
- atomicReference
3. 划重点
lamda不能修改外部引用的变量的原因其实也很简单,本质上就是因为lambda表达式在方法内部,那么lambda表达式的内存分配就是在栈上。栈内存不存在线程安全问题,因为栈内存存的都是变量的副本。
对于局部变量count而言,它的生命周期就是所在方法的生命周期。这就决定了count无法被位于同一个栈帧上的lambda修改,因为这种修改毫无意义,
你无法将你的修改传递出当前栈帧。栈内存不会被共享,也就意味着你没有权利和其他栈帧通信。
如果非要在lambda内部修改lambda表达式外部的局部变量的值呢?
有两种方式:使用数组或者把局部变量定义为全局变量。
这2种方式,其实本质是一样的:内存都分配在堆上。这就决定了,使用这2种方式来修改变量的值,是可行的。
转载请注明出处:www.meidanlong