感谢原文:https://blog.csdn.net/u010393325/article/details/80643636

因为生命周期的原因。方法中的局部变量,方法结束后这个变量就要释放掉,final保证这个变量始终指向一个对象。首先,内部类和外部类其实是处于同一个级别,内部类不会因为定义在方法中就会随着方法的执行完毕而跟随者被销毁。问题就来了,如果外部类的方法中的变量不定义final,那么当外部类方法执行完毕的时候,这个局部变量肯定也就被GC了,然而内部类的某个方法还没有执行完,这个时候他所引用的外部变量已经找不到了。如果定义为final,java会将这个变量复制一份作为成员变量内置于内部类中,这样的话,由于final所修饰的值始终无法改变,所以这个变量所指向的内存区域就不会变。 为了解决:

局部变量的生命周期与局部内部类的对象的生命周期的不一致性问题

编程时,在线程中使用局部变量时候经常编译器会提示:局部变量必须声明为final

package test;

public class ThreadTest {

	public void function(String a) {

		new Thread(){
@Override
public void run() {
System.out.println(a);
}
}.start();
} public static void main(String[] args) {
new ThreadTest().function("a"); }
}

上图中由于方法function中的形参a没有声明为final,编译抛出异常:Cannot refer to the non-final local variable a defined in an enclosing scope

其实原因就是一个规则:java内部类访问局部变量时局部变量必须声明为final。

public class ThreadTest {

	public void function(String a) {
a="b";
new Thread(){
@Override
public void run() {
System.out.println(a);
}
}.start();
} public static void main(String[] args) {
new ThreadTest().function("a"); }
}

在a="b"这一行报错:Local variable a defined in an enclosing scope must be final or effectively final

也就是说规则没有改变,只是java1.8的编译变得更加智能了而已,在局部变量没有重新赋值的情况下,它默认局部变量为final型,认为你只是忘记加final声明了而已。如果你重新给局部变量改变了值或引用,那就无法默认为final了,所以报错


补充:

对局部变量有要求具体如下:

(1)内部类里面使用外部类的局部变量时,其实就是内部类的对象在使用它,内部类对象生命周期中都可能调用它, 而内部类试图访问外部方法中的局部变量时,外部方法的局部变量很可能已经不存在了,那么就得延续其生命, 拷贝到内部类中,而拷贝会带来不一致性,从而需要使用final声明保证一致性。说白了,内部类会自动拷贝外部变量 的引用,为了避免:

外部方法修改引用,而导致内部类得到的引用值不一致

内部类修改引用,而导致外部方法 的参数值在修改前和修改后不一致。于是就用 final 来让该引用不可改变。

(2)内部类通常都含有回调,引用那个匿名内部类的函数执行完了就没了,所以内部类中引用外面的局部变量需要 是final的,这样在回调的时候才能找到那个变量,而如果是外部类的成员变量就不需要是final的,因为内部类本身 都会含有一个外部类的引用(外部类.this),所以回调的时候一定可以访问到

原文链接:https://www.jianshu.com/p/3fe608b865bb

为什么内部类调用的外部变量必须是final修饰的?的更多相关文章

  1. 为什么内部类访问的外部变量需要使用final修饰

    因为生命周期的原因.方法中的局部变量,方法结束后这个变量就要释放掉,final保证这个变量始终指向一个对象.首先,内部类和外部类其实是处于同一个级别,内部类不会因为定义在方法中就会随着方法的执行完毕而 ...

  2. 一个注意事项:内部类引用的外部变量必须是final的

    之前写过一个项目,好久没更新了,最近翻起以前的代码,发现在这里报了一个错.(现在转到Intellij了,从前在Eclipse luna中是可以编译通过的,Eclipse mars也会报错,JDK版本都 ...

  3. 为什么局部内部类中访问同一方法中的变量,该变量一定要是final修饰的

     最近有一个疑惑:为什么局部内部类中访问同一方法中的变量,该变量一定要是final修饰的         首先,我们看一个局部内部类的例子:             class OutClass {  ...

  4. 内部类访问局部变量为什么必须要用final修饰

    内部类访问局部变量为什么必须要用final修饰 看了大概五六篇博客, 讲的内容都差不多, 讲的内容也都很对, 但我觉得有些跑题了 略叙一下 String s = "hello"; ...

  5. 内部类访问局部变量的时候,为什么变量必须加上final修饰

    这里的局部变量就是在类方法中的变量,能访问方法中变量的类当然也是局部内部类了.我们都知道,局部变量在所处的函数执行完之后就释放了,但是内部类对象如果还有引用指向的话它是还存在的.例如下面的代码: cl ...

  6. 为什么在匿名内部类中引用外部对象要加final修饰符

    当所在的方法的形参需要被内部类里面使用时,该形参必须为final. 为什么必须要为final呢? 首先我们知道在内部类编译成功后,它会产生一个class文件,该class文件与外部类并不是同一clas ...

  7. awk引用外部变量及调用系统命令方法

    目标:想用awk与scp命令批量传送文件 前提:先搭好主机间的免密登陆环境(参考:http://www.cnblogs.com/tankaixiong/p/4172942.html) 实现脚本方法: ...

  8. 内部类访问外部类的变量必须是final吗,java静态方法中不能引用非静态变量,静态方法中不能创建内部类的实例

    内部类访问外部类的变量必须是final吗? 如下: package com.java.concurrent; class A { int i = 3; public void shout() { cl ...

  9. PHP变量入门教程(4)PHP 的外部变量

    PHP 的外部变量 HTML 表单(GET 和 POST) 当一个表单体交给 PHP 脚本时,表单中的信息会自动在脚本中可用.有很多方法访问此信息,例如: 一个简单的 HTML 表单 <form ...

随机推荐

  1. 【优雅代码】02-java传个方法你会吗,不是Method对象

    [优雅代码]02-java传个方法你会吗,不是Method对象 欢迎关注b站账号/公众号[六边形战士夏宁],一个要把各项指标拉满的男人.该文章已在github目录收录. 屏幕前的大帅比和大漂亮如果有帮 ...

  2. Java初学者作业——编写 Java 程序,用户输入 3 个操作数,分别求出最大值、最小值和平均值。

    返回本章节 返回作业目录 需求说明: 编写 Java 程序,用户输入 3 个操作数,分别求出最大值.最小值和平均值. 实现思路: 定义 Java 类,定义 3 个方法,用来求 3 个数字的最大值.最小 ...

  3. 基于GO语言实现的固定长度邀请码

    1. 选取数字加英文字母组成32个字符的字符串,用于表示32进制数. 2. 用一个特定的字符比如`G`作为分隔符,解析的时候字符`G`后面的字符不参与运算. 3. LEN表示邀请码长度,默认为6. g ...

  4. Swoole 进程管理模块 Process 之单进程的使用

    PHP 自带的 pcntl,存在很多不足,如: 没有提供进程间通信的功能: 不支持重定向标准输入和输出: 只提供了 fork 这样原始的接口,容易使用错误: Swoole\Process 提供了如下特 ...

  5. CSS基础6之盒子模型1

    盒子概述 以下是盒子模型的一个图形解释 一.内边距(填充) 属性有: (1) padding  设置所有内边距 (2) padding-top  设置上边距 (3) padding-left 设置左边 ...

  6. Pond Skater

    题目 Snuke,水上平衡车,住在一个矩形池塘,可以看成 H 列 W 行,(i, j) 表示第 i 列第 j 行.池塘里长着荷叶,荷叶是不能进入的.如果 cij 是 @,表示荷叶.如果 cij 是 . ...

  7. Hive实现网站PV分析

    原文链接: https://www.toutiao.com/i6773241257528394248/ 之前我们做过<java mapreduce实现网站PV分析>,这次我们可以用hive ...

  8. Hive的连接和运行模式

    原文链接: https://www.toutiao.com/i6771018203687551495/ Hive的连接 启动hadoop的时候将history也启动,如果出问题,可以方便我们后续定位 ...

  9. less 循环模拟sass的for循环效果

    // 输入框部分宽度 从10px到600px 相隔10像素 .generate-widths(600); .generate-widths(@n, @i: 10) when (@i =< @n) ...

  10. 使用altium designer 21极坐标绘制异形焊盘 比如焊接螺母的 环绕焊盘

    先看一张图 在回流焊时,不能直接做一个大圆圈焊盘来焊接螺母,这样焊锡膏因为流动问题,可能会导致螺母歪斜 厂家推荐的焊盘形状右上角 所以 需要绘制异形焊盘 首先进入ad的封装库工作界面 在库中点右下角P ...