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,代码如下: ...
随机推荐
- Javascript中没有块级作用域(模仿)
在C/C++中,由花括号封闭的代码块都有自己的作用域,也就是块级作用域(私有作用域).而在javascript中则没有块级作用域,首先来看一段代码: function test(){ for(var ...
- spring MVC(十)---spring MVC整合mybatis
spring mvc可以通过整合hibernate来实现与数据库的数据交互,也可以通过mybatis来实现,这篇文章是总结一下怎么在springmvc中整合mybatis. 首先mybatis需要用到 ...
- app后端设计(4)-- 通讯的安全性
在app的后台设计中,一个很重要的因素是考虑通讯的安全性. 因此,我们需要考虑的要点有: 1. 在app和后台,都不能保存任何用户密码的明文 2. 在app和后台通讯的过程中,怎么保证用户信息的安全性 ...
- mongoDB的安装及基本使用
1.mongoDB简介 1.1 NoSQL数据库 数据库:进行高效的.有规则的进行数据持久化存储的软件 NoSQL数据库:Not only sql,指代非关系型数据库 优点:高可扩展性.分布式计算.低 ...
- &&和&、||和|的区别
&& 和 || 为短路与 短路或&&若前面的表达式为false,整个逻辑表达式为false,所以后面的表达式无论true和false都无法影响整个表达式的逻辑结果,所以 ...
- BZOJ_2962_序列操作_线段树
Description 有一个长度为n的序列,有三个操作1.I a b c表示将[a,b]这一段区间的元素集体增加c,2.R a b表示将[a,b]区间内所有元素变成相反数,3.Q a b c表示询问 ...
- Windbg分析高内存占用问题
1. 问题简介 最近产品发布大版本补丁更新,一商超客户升级后,反馈系统经常奔溃,导致超市的收银系统无法正常收银,现场排队付款的顾客更是抱怨声声.为了缓解现场的情况, 客户都是手动回收IIS应用程序池才 ...
- 详解线程池execute和submit用法
在使用线程池时,我们都知道线程池有两种提交任务的方式,那么他们有什么区别呢? 1.execute提交的是Runnable类型的任务,而submit提交的是Callable或者Runnable类型的任务 ...
- 使用elementUI的时候,使用Upload 上传的时候,使用 list-type 属性来设置文件列表的样式,before-upload方法失效
最近在做项目的时候,使用elementUI的时候,使用Upload 上传的时候,before-upload方法失效. 情况下:使用 list-type 属性来设置文件列表的样式. 最终的优化之后:(演 ...
- 国内开源社区巨作AspectCore-Framework入门
前些天和张队(善友),lemon(浩洋),斌哥(项斌)等MVP大咖一块儿吃饭,大家聊到了lemon名下的AOP这个项目,我这小白听得一脸懵逼,后面回来做了一下功课,查了下资料,在lemon的Githu ...