lambda和匿名内部类使用外部变量为什么要语义final?
今天群里讨论java
的lambda
实现.
后来不断衍生谈到了为什么lambda和匿名内部类只能使用语义final
的外部变量.
最开始以为是java的lambda实现问题,编译期魔法会把外部引用作为参数传入所以在内部变化也影响不了下次调用的值,所以就干脆final了,如果用类的属性来保管这个变量就可以了.
In [64]: def outer(a:int):
...: def inner():
...: nonlocal a
...: a = a + a
...: return a
...: return inner
...:
In [65]: x = outer(1)
In [66]: x
Out[66]: <function __main__.outer.<locals>.inner>
In [67]: x()
Out[67]: 2
In [68]: x()
Out[68]: 4
In [69]: x()
Out[69]: 8
举例就是这种情况
lambda用参数传入外部int,如果在方法里修改了,下次调用这个lambda依旧是以前的值.
后来又去看了眼匿名内部类的实现
public class InnerTest {
public static void main(String[] args) {
String name = "123";
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println(name);
}
};
r.run();
}
}
InnerTest$1(java.lang.String val$name);
0 aload_0 [this]
1 aload_1 [val$name]
2 putfield InnerTest$1.val$name : java.lang.String [12]
5 aload_0 [this]
6 invokespecial java.lang.Object() [14]
9 return
Line numbers:
[pc: 0, line: 1]
[pc: 5, line: 11]
Local variable table:
[pc: 0, pc: 10] local: this index: 0 type: new InnerTest(){}
Method Parameters:
final synthetic val$name
构造方法字节码明明都存下来了呀...为什么那时候就要求final
了
查阅了一下,发现这样有个很大的问题.
这个外部变量在匿名内部类初始化之后就被固定了下来,之后他如果被重新赋值(引用类型内部状态修改除外),就会出现内部无法看见外部,外部也无法看见内部的问题... ...
举个简单的例子:
In [101]: def outer(x):
...: def inner():
...: nonlocal x
...: x = x+1
...: print("inner"+str(x))
...: inner()
...: print("outer"+str(x))
...: x = x+1
...: inner()
...:
In [102]: outer(1)
inner2(inner内部+1)
outer2(外部看到这个变化)
inner4(外部+1 内部+1)
这段在py下能正常工作的代码,如果java没有final
限制的话,就会变成
inner2(inner内部+1)
outer1(外部看不到inner变化)
inner3(inner内部+1)
所以这个约定和闭包实现没关系...
还是考虑在定义变量的作用域下规避掉因为java实现问题导致上面的结果返回...我既然没有nonlocal
这样的机制(毕竟不支持引用传递....),索性就用final
限制起来.
呜呼哀哉
参考资料:
Closure_(computer_programming)
lambda和匿名内部类使用外部变量为什么要语义final?的更多相关文章
- 为什么Java中lambda表达式不能改变外部变量的值,也不能定义自己的同名的本地变量呢?
作者:blindpirate链接:https://www.zhihu.com/question/361639494/answer/948286842来源:知乎著作权归作者所有.商业转载请联系作者获得授 ...
- 关于Lambda表达式访问外部变量
在<C#高级编程>一书中提到通过Lambda表达式可以访问Lambda表达式块外部的变量 ,这是一个很好的功能(类似Js中的 闭包).但是如果没有正确的使用,会非常危险. 比如下面的事例中 ...
- 匿名内部类中使用的外部局部变量为什么只能是final变量
被匿名内部类引用的变量会被拷贝一份到内部类的环境中 但其后,在外部,该变量如果被修改,则内部外部不一致 Java为了避免数据不同步的问题,做出了匿名内部类只可以访问final的局部变量的限制. 究其原 ...
- python函数定义中引用外部变量的一个问题
如果在函数定义的默认值中引用了一个外部变量,如下所示 x = 3 def func(a = x): print(a, x) 那么a的默认值就会是3, 但是print语句中的x会是调用时的x值 lamb ...
- 为什么内部类调用的外部变量必须是final修饰的?
感谢原文:https://blog.csdn.net/u010393325/article/details/80643636 因为生命周期的原因.方法中的局部变量,方法结束后这个变量就要释放掉,fin ...
- PHP变量入门教程(4)PHP 的外部变量
PHP 的外部变量 HTML 表单(GET 和 POST) 当一个表单体交给 PHP 脚本时,表单中的信息会自动在脚本中可用.有很多方法访问此信息,例如: 一个简单的 HTML 表单 <form ...
- 【C语言】C语言外部变量和内部变量
目录: [外部变量] · 定义 · 用extern修饰变量 [内部变量] · 定义 · 用static修饰变量 1.外部变量 · 定义 定义的变量能被本文件和其它文件访问的变量,称为外部变量. 注: ...
- awk引用外部变量及调用系统命令方法
目标:想用awk与scp命令批量传送文件 前提:先搭好主机间的免密登陆环境(参考:http://www.cnblogs.com/tankaixiong/p/4172942.html) 实现脚本方法: ...
- ajax 外部变量
1.一般的js代码可以放在任何位置.但是用jquery写的代码需要先引入jquery文件,再写代码. 2.ajax函数中内部的变量不能传到外部.如果改变外部变量,需要async:false,代码如下: ...
随机推荐
- 关于for循环里面异步操作的问题
首先来看一个比较简单的问题,我们想实现的就是每隔1s输出0-4的值,就是这么简单,看下错误写法: function test() { for (var i = 0; i < 5; ++i) { ...
- DD XOFT虚拟键盘鼠标
下载:http://www.ddxoft.com/ 简介:最多用户选择,最简单易用,最稳定可靠 永久免费 系统底层集成,真正的驱动级硬件模拟 一键安装,即为电脑添加一对可完全编程控制的键盘鼠标,轻松自 ...
- WeTest----如何查看Wetest生成测试报告?
在前一篇文章中主要介绍了手机中如何开始进行WeTest测试,此篇文章将总结测试报告的查看,这里很简单啦,一切的测试结果wetest都将自动生成,值得注意的是,新注册的用户默认每项测试次数为5,所以请珍 ...
- json数组的解析
一直以来,经常会遇到json数据从前端或者我经常从网站上爬取的数据中会有json数据的存在,这样如果想要获取json数据就需要对json数据进行解析 在开发过程中,经常需要和别的系统交换数据,数据交换 ...
- 开源)嗨,Java,你可以生成金山词霸的二维码分享海报吗?
As long as you can still grab a breath, you fight.只要一息尚存,就不得不战. 有那么一段时间,我特别迷恋金山词霸的每日一句分享海报.因为不仅海报上的图 ...
- WebP 在减少图片体积和流量上的效果如何?MIP技术实践分享
作者 | Jackson 编辑 | 尾尾 不论是 PC 还是移动端,图片一直占据着页面流量的大头,在图片的大小和质量之间如何权衡,成为了长期困扰开发者们的问题.而 WebP 技术的出现,为解决该问题提 ...
- 腾讯云存储专家深度解读基于Ceph对象存储的混合云机制
背景 毫无疑问,乘着云计算发展的东风,Ceph已经是当今最火热的软件定义存储开源项目.如下图所示,它在同一底层平台之上可以对外提供三种存储接口,分别是文件存储.对象存储以及块存储,本文主要关注的是对象 ...
- python接口自动化(十四)--session关联接口(详解)
简介 上一篇cookie绕过验证码模拟登录博客园,但这只是第一步,一般登录后,还会有其它的操作,如发帖,评论等等,这时候如何保持会话呢?这里我以jenkins平台为例,给小伙伴们在沙场演练一下. se ...
- 利用ATiny85制作BadUSB
0x00.准备: ATiny85的板子 淘宝十元包邮.有两款,两款都可以,建议选择左边的,这样可以直接插入USB口,第二款也可以,不过需要一根Micro的数据线(旧款安卓手机使用的线). 电脑安装驱动 ...
- Java核心技术梳理-基础类库
一.引言 Oracle为Java提供了丰富的基础类库,Java 8 提供了4000多个基础类库,熟练掌握这些基础类库可以提高我们的开发效率,当然,记住所有的API是不可能也没必要的,我们可以通过API ...