感谢原文: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. GPT and BERT

    目录 概 主要内容 GPT BERT Radford A., Narasimhan K., Salimans T. and Sutskever I. Improving language unders ...

  2. JDK HttpClient 单次请求的生命周期

    HttpClient 单次请求的生命周期 目录 HttpClient 单次请求的生命周期 1. 简述 2. uml图 3. Http连接的建立.复用和降级 3.1 调用流程及连接的建立和复用 3.2 ...

  3. 2021前端面试css(三)

    overflow 原理 块格式化上下文是css可视化渲染的一部分,它是一块区域,规定了内部块盒的渲染方式,以及浮动相互之间的影响关系,当元素设置了overflow 样式且值不为visible时,元素就 ...

  4. jquery控制元素的隐藏和显示的几种方法

    使用jquery控制div的显示与隐藏,一句话就能搞定,例如: 方法一 显示: $("#id").show()表示为display:block, 隐藏: $("#id&q ...

  5. Java练习小题_猴子吃桃问题分别用for循环和while循环实现程序。

    要求说明: 猴子吃桃问题:猴子第一天摘下若干个桃子,当即吃了一半,还不瘾,又多吃了一个第二天早上又将剩下的桃子吃掉一半,又多吃了一个.以后每天早上都吃了前一天剩下的一半零一个.到第10天早上想再吃时, ...

  6. Java Swing设计简单商品信息管理系统(java swing+mysql+eclipse)

    一.概述 为了管理好商店库存信息,提升店铺管理工作效率,结合实际工作需要,设计和开发本系统,主要用于商店商品信息维护出入库等.包含商品库存信息查看.商品信息修改,新增商品信息,删除信息等功能. 二.功 ...

  7. Lombok的利弊

    1.介绍 Lombok是一个可以大量减少代码的工具, 通过Pluggable Annotation Processing API的方式解析注解, 在编译期为class文件注入getter,setter ...

  8. python+openpyxl 获取最大行数,不是真正想获取的行数,导致替换时,报”NoneType' object has no attribute 'find'

    问题描述: 使用excel对接口的数据进行管理,添加接口数据时,可能习惯性选择多行,设置了格式,导致多选了很多空行也被设置了格式,在读取这个sheet的最大行数时,发现有问题,获取到了为None的空行 ...

  9. [flask] jinja自定义filter来过滤html标签

    问题描述 数据库存储了html格式的博客文章,在主页(index)显示的时候带有html标签,如何过滤掉呢? 解决方案 用jinja自定义filter过滤掉html标签 我是用的工厂函数,因此在工厂函 ...

  10. 在 CentOS 7 上安装和配置 Puppet

    1 准备 2台 centos7 (master/server:192.168.1.103 agent/client:192.168.1.106) 分别添加puppet自定义仓库 https://yum ...