我们都知道方法中的匿名/局部内部类是能够访问同一个方法中的局部变量的,但是为什么局部变量要加上一个final呢?

首先我们来研究一下变量生命周期的问题,局部变量的生命周期是当该方法被调用时在栈中被创建,当方法调用结束时(执行完毕),退栈,这些局部变量就会死亡。但是内部类对象是创建在堆中的,其生命周期跟其它类一样,只有当jvm用可达性分析法发现这个对象通过GCRoots节点已经不可达,然后进行gc才会死亡。

所以完全有可能存在的一个现象就是一个方法已经调用结束(局部变量已死亡),但该内部类的对象仍然活着,也就是说内部类创建的对象的生命期会超过局部变量,这就会出现内部类的对象要访问局部变量时访问失败,而java为了保证这种情况不会发生,就用了一种折中的方案:内部类要访问局部变量,局部变量必须加final,那为什么局部变量定义成final就可以了呢?

然后我们再来看final这个关键字修饰变量的特点:当final修饰一个基本数据类型的变量时,这个基本类型的变量在初始化的时候就应该赋值,并且初始化完成之后其值就不能再发生改变了;当final修饰一个引用类型的变量时,这个引用类型的变量在初始化的时候就应该赋值并且之后不能再发生改变,但是引用类型的变量指向的对象的堆内存的值是可以改变的。

基于final修饰变量的以上两个特点,java就把局部内部类对象要访问的final型局部变量,复制过来变成该内部类对象中的一个成员变量,这样即使栈中局部变量(含final)已死亡,但由于它是final的,其值是不会发生改变的,因而内部类对象在局部变量死亡后,照样可以访问自己内部维护的一个值跟局部变量一样的成员变量,从而解决这个问题。

ps:java8中匿名/局部内部类访问局部变量时,局部变量已经可以不用加final了,但其实这个局部变量还是final的,只不过不用显式的加上而已,推测可能是编译机制发生了改变。

匿名/局部内部类访问局部变量时,为什么局部变量必须加final的更多相关文章

  1. 内部类访问局部变量时,为什么需要加final关键字

    是变量的作用域的问题,因为匿名内部类是出现在一个方法的内部的,如果它要访问这个方法的参数或者方法中定义的变量,则这些参数和变量必须被修饰为final.因为虽然匿名内部类在方法的内部,但实际编译的时候, ...

  2. 局部内部类访问方法中的局部变量为什么加final

    转载:http://www.cnblogs.com/mjblogs/p/4971630.html 1)从程序设计语言的理论上:局部内部类(即:定义在方法中的内部类),由于本身就是在方法内部(可出现在形 ...

  3. 局部内部类访问它所在方法的局部变量时,要求该局部变量必须声明为final的原因

    这是java的一条规则.那么为什么会有这条规则呢?要想弄懂这个问题,就需要弄懂局部内部类对象和局部变量的生命周期的谁更长的问题. 首先,看一段代码,以没有将变量声明为final的代码作为例子,代码如下 ...

  4. java-内部类访问特点-私有成员内部类-静态成员内部类-局部内部类访问局部变量

    1.内部类访问特点: - 内部类可以直接访问外部类的成员,包括私有. - 外部类要访问内部类的成员,必须创建对象. - 外部类名.内部类名 对象名 = 外部类对象.内部类对象: - 例: class ...

  5. 为什么局部内部类访问外边的局部变量必须为final

    6.局部内部类访问外边的局部变量时,此变量必须为final类型 马克-to-win:由于技术方面的限制,java的设计者们做出如下语法规定:局部内部类访问外边的局部变量时,此变量必须为final类型, ...

  6. 细说匿名内部类引用方法局部变量时为什么需要声明为final

    一.前言 在研究公司某个项目的源码,看到前人使用了挺多内部类,内部类平时我用的比较多的是匿名内部类,平时用的多的是匿名内部类,其他形式的用的比较少,然后我就有个疑惑:到底内部类是基于什么样的考虑,才让 ...

  7. C#的匿名委托 和 Java的匿名局部内部类

    .NET:C#的匿名委托 和 Java的匿名局部内部类 目录 背景实验备注 背景返回目录 这几天重温Java,发现Java在嵌套类型这里提供的特性比较多,结合自身对C#中匿名委托的理解,我大胆的做了一 ...

  8. “全栈2019”Java第九十八章:局部内部类访问作用域成员详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  9. .NET:C#的匿名委托 和 Java的匿名局部内部类

    背景 这几天重温Java,发现Java在嵌套类型这里提供的特性比较多,结合自身对C#中匿名委托的理解,我大胆的做了一个假设:Java的字节码只支持静态嵌套类,内部类.局部内部类和匿名局部内部类都是编译 ...

随机推荐

  1. 牛客多校第五场 G subsequence 1 最长公共子序列/组合数

    题意: 给定两个由数字组成的序列s,t,找出s所有数值大于t的子序列.注意不是字典序大. 题解: 首先特判s比t短或一样长的情况. 当s比t长时,直接用组合数计算s不以0开头的,长度大于t的所有子序列 ...

  2. MongoDB错误记录

    文章目录 mongoDB启动报错 mongoDB启动报错 在bin目录下执行 ./mongod 报错如下 F CONTROL [main] Failed global initialization: ...

  3. laravel请求处理管道例子

    例子: <?php interface Middleware{ public static function handle (Closure $next);} class VerifyCsrfT ...

  4. Ubuntu下搭建Pixhawk开发环境

    安装提示 需要网络环境,不然下载会很慢. 工具安装 1. 权限设置 sudo usermod -a -G dialout $USER 代码输入可以拷贝,但是不可以用快捷键. 需要输入密码,输入密码无显 ...

  5. datagrid 的标题的内容不对应整齐

    $(document).ready(function(){ var column = "[["+ "{'title':'工号','field':'grantorCode' ...

  6. 数据类中引用virtual

    public class City { [Key] public int CityID { set; get; } [Display(Name = "城市名称")] [Requir ...

  7. virtualbox导入winXP系统OVA文件重启

    1,开启虚拟机 2,按f8进入安全模式,然后修改注册表: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Processor HKEY_LOC ...

  8. 四. (TDZ)展示性死区

    在ES6中怎么使用 var Let const ? 1.var 声明之前 2. let 声明之前 3. const声明之前

  9. 2-sat——hdu3062基础

    hdu就是会卡cin,, 另一种建模方式,把点i拆成i*2,i*2+1,有时候这样会比较简单 #include<bits/stdc++.h> using namespace std; #d ...

  10. C#一般处理程序设置和读取session(session报错“未将对象引用设置到对象的实例”解决)

    登陆模块时,用到了session和cookie.在一般处理程序中处理session,一直报错.最后找到问题原因是需要调用 irequiressessionstate接口. 在ashx文件中,设置ses ...