匿名/局部内部类访问局部变量时,为什么局部变量必须加final

我们都知道方法中的匿名/局部内部类是能够访问同一个方法中的局部变量的,但是为什么局部变量要加上一个final呢?
首先我们来研究一下变量生命周期的问题,局部变量的生命周期是当该方法被调用时在栈中被创建,当方法调用结束时(执行完毕),退栈,这些局部变量就会死亡。但是内部类对象是创建在堆中的,其生命周期跟其它类一样,只有当jvm用可达性分析法发现这个对象通过GCRoots节点已经不可达,然后进行gc才会死亡。
所以完全有可能存在的一个现象就是一个方法已经调用结束(局部变量已死亡),但该内部类的对象仍然活着,也就是说内部类创建的对象的生命期会超过局部变量,这就会出现内部类的对象要访问局部变量时访问失败,而java为了保证这种情况不会发生,就用了一种折中的方案:内部类要访问局部变量,局部变量必须加final,那为什么局部变量定义成final就可以了呢?
然后我们再来看final这个关键字修饰变量的特点:当final修饰一个基本数据类型的变量时,这个基本类型的变量在初始化的时候就应该赋值,并且初始化完成之后其值就不能再发生改变了;当final修饰一个引用类型的变量时,这个引用类型的变量在初始化的时候就应该赋值并且之后不能再发生改变,但是引用类型的变量指向的对象的堆内存的值是可以改变的。
基于final修饰变量的以上两个特点,java就把局部内部类对象要访问的final型局部变量,复制过来变成该内部类对象中的一个成员变量,这样即使栈中局部变量(含final)已死亡,但由于它是final的,其值是不会发生改变的,因而内部类对象在局部变量死亡后,照样可以访问自己内部维护的一个值跟局部变量一样的成员变量,从而解决这个问题。
ps:java8中匿名/局部内部类访问局部变量时,局部变量已经可以不用加final了,但其实这个局部变量还是final的,只不过不用显式的加上而已,推测可能是编译机制发生了改变。
匿名/局部内部类访问局部变量时,为什么局部变量必须加final的更多相关文章
- 内部类访问局部变量时,为什么需要加final关键字
是变量的作用域的问题,因为匿名内部类是出现在一个方法的内部的,如果它要访问这个方法的参数或者方法中定义的变量,则这些参数和变量必须被修饰为final.因为虽然匿名内部类在方法的内部,但实际编译的时候, ...
- 局部内部类访问方法中的局部变量为什么加final
转载:http://www.cnblogs.com/mjblogs/p/4971630.html 1)从程序设计语言的理论上:局部内部类(即:定义在方法中的内部类),由于本身就是在方法内部(可出现在形 ...
- 局部内部类访问它所在方法的局部变量时,要求该局部变量必须声明为final的原因
这是java的一条规则.那么为什么会有这条规则呢?要想弄懂这个问题,就需要弄懂局部内部类对象和局部变量的生命周期的谁更长的问题. 首先,看一段代码,以没有将变量声明为final的代码作为例子,代码如下 ...
- java-内部类访问特点-私有成员内部类-静态成员内部类-局部内部类访问局部变量
1.内部类访问特点: - 内部类可以直接访问外部类的成员,包括私有. - 外部类要访问内部类的成员,必须创建对象. - 外部类名.内部类名 对象名 = 外部类对象.内部类对象: - 例: class ...
- 为什么局部内部类访问外边的局部变量必须为final
6.局部内部类访问外边的局部变量时,此变量必须为final类型 马克-to-win:由于技术方面的限制,java的设计者们做出如下语法规定:局部内部类访问外边的局部变量时,此变量必须为final类型, ...
- 细说匿名内部类引用方法局部变量时为什么需要声明为final
一.前言 在研究公司某个项目的源码,看到前人使用了挺多内部类,内部类平时我用的比较多的是匿名内部类,平时用的多的是匿名内部类,其他形式的用的比较少,然后我就有个疑惑:到底内部类是基于什么样的考虑,才让 ...
- C#的匿名委托 和 Java的匿名局部内部类
.NET:C#的匿名委托 和 Java的匿名局部内部类 目录 背景实验备注 背景返回目录 这几天重温Java,发现Java在嵌套类型这里提供的特性比较多,结合自身对C#中匿名委托的理解,我大胆的做了一 ...
- “全栈2019”Java第九十八章:局部内部类访问作用域成员详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...
- .NET:C#的匿名委托 和 Java的匿名局部内部类
背景 这几天重温Java,发现Java在嵌套类型这里提供的特性比较多,结合自身对C#中匿名委托的理解,我大胆的做了一个假设:Java的字节码只支持静态嵌套类,内部类.局部内部类和匿名局部内部类都是编译 ...
随机推荐
- Delphi代码创建形式规范 1.0
Delphi代码创建形式规范 1.0 本规范的目的:给自己的代码一个统一而标准的外观,增强 可读性,可理解性,可维护性 本规范的原则:名称反映含义,形式反映结构 1.单元风格 ...
- git工作区和暂存区图
- spring boot中使用javax.validation以及org.hibernate.validator校验入参
这里springboot用的版本是:<version>2.1.1.RELEASE</version> 自带了hibernate.validator,所以不用添加额外依赖 1.创 ...
- DNA repair HDU - 2457 AC自动机+DP
题意: 给你N个模板串,并且给你一个文本串, 现在问你这个文本串最少需要改变几个字符才能使得它不包含任何模板串. (以上字符只由A,T,G,C构成) 题解: 刚开始做这一题的时候表示很懵逼,好像没有学 ...
- input 数值验证
1.手动校验数字为整数 Number.isInteger <el-input class="radioInput" v-model.number="ruleForm ...
- JS 根据今天的日期获取本周星期一与星期天的日期
var now = new Date(); var nowTime = now.getTime() ; var day = now.getDay(); var oneDayTime = 24*60*6 ...
- 6月份Github上最热门的Java开源项目!
1.halo 这是一个轻快,简洁,功能强大,使用Java开发的博客系统. 项目地址:https://github.com/halo-dev/halo Star 6139 2.jeecg-boot ...
- PAT甲级——A1082 Read Number in Chinese
Given an integer with no more than 9 digits, you are supposed to read it in the traditional Chinese ...
- myeclipse 无法部署项目到jboss服务器 部署不上去
关于myeclipse部署项目到jboss点击add deployments没有反应的问题,如图 此处点击右键,选择add deployments没有反应,原因是默认的web-root folder为 ...
- 群晖系统下btfs(占用5%)和ext4文件格式的硬盘占用和选择
1个人感觉选择ext4就可以,毕竟重要数据会设置raid1 不重要的数据也不需要快照什么的 商用除外 对于一个4t的硬盘 实际容量3726G 使用ext4可用空间3666G,群晖 占用60G大概1.6 ...