为什么必须是final的呢?
一个谜团
如果你用过类似guava这种“伪函数式编程”风格的library的话,那下面这种风格的代码对你来说应该不陌生:
1 |
|
这段代码对一个字符串的list进行过滤,从中找出长度为4的字符串。看起来很是平常,没什么特别的。
但是,声明expectedLength时用的那个final看起来有点扎眼,把它去掉试试:
error: local variable expectedLength is accessed from within inner class; needs to be declared final
结果Java编译器给出了如上的错误,看起来匿名内部类只能够访问final的局部变量。但是,为什么呢?其他的语言也有类似的规定吗?
在开始用其他语言做实验之前我们先把问题简化一下,不要再带着guava了,我们去除掉噪音,把问题归结为:
为什么Java中的匿名内部类只可以访问final的局部变量呢?其他语言中的匿名函数也有类似的限制吗?
Scala中有类似的规定吗?
1 |
|
上面的Scala代码是合法的,number变量是声明为var的,不是val(类似于Java中的final)。而且在匿名函数中可以修改number的值。
看来Scala中没有类似的规定。
C#中有类似的规定吗?
1 |
|
这段C#代码也是合法的,number这个局部变量在lambda表达式内外都可以访问和赋值。
看来C#中也没有类似的规定。
分析谜团
三门语言中只有Java有这种限制,那我们分析一下吧。先来看一下Java中的匿名内部类是如何实现的:
先定义一个接口:
1 |
|
然后创建这个接口的匿名子类:
1 |
|
这个匿名子类会被编译成一个单独的类,反编译的结果是这样的:
1 |
|
可以看到名为number的局部变量是作为构造方法的参数传入匿名内部类的(以上代码经过了手动修改,真实的反编译结果中有一些不可读的命名)。
如果Java允许匿名内部类访问非final的局部变量的话,那我们就可以在TryUsingAnonymousClass$1中修改paramInteger,但是这不会对number的值有影响,因为它们是不同的reference。
这就会造成数据不同步的问题。
所以,谜团解开了:Java为了避免数据不同步的问题,做出了匿名内部类只可以访问final的局部变量的限制。
但是,新的谜团又出现了:
Scala和C#为什么没有类似的限制呢?它们是如何处理数据同步问题的呢?
上面出现过的那段Scala代码中的lambda表达式会编译成这样:
1 |
|
可以看到number也是通过构造方法的参数传入的,但是与Java的不同是这里的number不是直接传入的,是被IntRef包装了一层然后才传入的。对number的值修改也是通过包装类进行的:this.number$2.elem = 456;
这样就保证了lambda表达式内外访问到的是同一个对象。
再来看看C#的处理方式,反编译一下,发现C#编译器生成了如下的一个类:
1 |
|
把number包装在这个类内,这样就保证了lambda表达式内外使用的都是同一个number,即便重新赋值也可以保证内外部的数据是同步的。
小结
Scala和C#的编译器通过把局部变量包装在另一个对象中,来实现lambda表达式内外的数据同步。
而Java的编译器由于未知的原因(怀疑是为了图省事儿?)没有做包装局部变量这件事儿,于是就只好强制用户把局部变量声明为final才能在匿名内部类中使用来避免数据不同步的问题。
为什么必须是final的呢?的更多相关文章
- java抽象、接口 和final
抽象 一.抽象类:不知道是具体什么东西的类. abstract class 类名 1.抽象类不能直接new出来. 2.抽象类可以没有抽象方法. public abstract class USB { ...
- Java内部类final语义实现
本文描述在java内部类中,经常会引用外部类的变量信息.但是这些变量信息是如何传递给内部类的,在表面上并没有相应的线索.本文从字节码层描述在内部类中是如何实现这些语义的. 本地临时变量 基本类型 fi ...
- Java关键字final、static
一.final根据程序上下文环境,Java关键字final有“这是无法改变的”或者“终态的”含义,它可以修饰非抽象类.非抽象类成员方法和变量.你可能出于两种理解而需要阻止改变:设计或效率. final ...
- JavaSE 之 final 初探
我们先看一道面试题: 请问 final 的含义是什么?可以用在哪里?其初始化的方式有哪些? 首先我们回答一下这道题,然后再探究其所以然. 1.final 表示“最终的”.“不可改变的”,意指其修饰类 ...
- PHP的final关键字、static关键字、const关键字
在PHP5中新增加了final关键字,它可以加载类或类中方法前.但不能使用final标识成员属性,虽然final有常量的意思,但在php中定义常量是使用define()函数来完成的. final关键字 ...
- final修饰符
final本身的含义是"最终的,不可变的",它可以修饰非抽象类,非抽象方法和变量.注意:构造方法不能使用final修饰,因为构造方法不能被继承,肯定是最终的. final修饰的类: ...
- 浅析Java中的final关键字(转载)
自http://www.cnblogs.com/dolphin0520/p/3736238.html转载 一.final关键字的基本用法 在Java中,final关键字可以用来修饰类.方法和变量(包括 ...
- java关键字extends(继承)、Supe(父类引用空间)、 This(方法调用者对象)、Instanceof(实例类型-判断对象是否属于某个类)、final(最终)、abstract(抽象) 、interface(接口)0
java 继承使用关键字extends 继承的作用:减少代码量,优化代码 继承的使用注意点: 1子类不能继承父类的私有变量 2.子类不能继承父类的构造方法 3.子类在调用自己的构造方法时 会默认调 ...
- files list file for package 'xxx' is missing final newline
#!/usr/bin/python # 8th November, 2009 # update manager failed, giving me the error: # 'files list f ...
- final关键字(final是最终的)
final关键字(final是最终的) 1.final修饰特点 a.修饰类,类不能被继承 b.修饰变量,变量就变成了常量, 修饰基本数据类:final int num = 10; 修饰引用数据类型变量 ...
随机推荐
- 【JQuery】eval()出现missing after property id 错误。
是因为数据没有转换成json格式输出就直接eval了. 正确步骤:后台: JsonBinder.buildNormalBinder().toJson(list); 前台: eval('(${posit ...
- git阶段学习总结
学习git大约有两个星期了,脑子里总算有点干货了,可以拿出来总结一下: git,用于版本控制的,刚开始觉得它是linux下默认的命令,其实也是个工具需要apt-get install git 安装一下 ...
- 通过SecureCRT和PuTTY连接臻云CentOS版云主机
原文地址:http://jingyan.baidu.com/article/fa4125acb6648128ac7092dc.html 如何通过SecureCRT和PuTTY工具远程连接臻云CentO ...
- Java学习笔记:内部类/匿名内部类的全面介绍
编写java程序时,一般一个类(或者接口)都是放在一个独立的java文件中,并且类名同文件名(如果类是public的,类名必须与文件名一致:非public得,无强制要求).如果想把多个java类放在一 ...
- php 父类子类构造函数注意事项
网上流传的2点: PHP的构造函数继承必须满足以下条件: 当父类有构造函数的声明时,子类也必须有声明,否则会出错. 在执行父类的构造函数时,必须在子类中引用parent关键字. 第1点不需要. 第二个 ...
- objective-C 初识
objective-C objective-c 是c语言的改进版 一.方法的定义: 格式: -/+(返回值类型)方法名:(参数类型) 参数名 [方法名] : (参数类型) 参数名......... 例 ...
- node.js 解析xml BOM问题(xmlreader sax.js)
Email:longsu2010 at yeah dot net 之前写了两篇文章关于node.js解析xml,说的是xmlreader,文章如下 node.js解析xml(xmlreader) no ...
- MySQL分组数据
分组 理解分组能够看例如以下一个样例,首先我们打印出products表例如以下 从上面的表中能够看出.每一个vendor都有若干个产品,那么怎么一次统计每一个vendor有多少个产品呢? 这里就能够使 ...
- Android平台下使用lua调用Java代码经验总结
动态语言以其执行的灵活性,可配置性.方便调试能够为开发带来极大的方便.假设用好了.能够极大的提高开发的效率. 怪不得像游戏开发这样复杂的软件开发里没有不集成脚本语言的. 当中,lua以其小巧,灵活.方 ...
- word2013 无endnote选项卡咋办
word2013 无endnote选项卡咋办? 前提: 已经安装了endnotex7,office word2013 word->文件->选项->加载项->最下面的 管理 &q ...