-
2020-03-01 23:34:15
因为生命周期不一致, 局部变量直接存储在栈中,当方法执行结束后,非final的局部变量就被销毁。而局部内部类对局部变量的引用依然存在,如果局部内部类要调用局部变量时,就会出错。加了final,可以确保局部内部类使用的变量与外层的局部变量区分开,解决了这个问题。
更多相关内容 -
匿名/局部内部类访问局部变量时,为什么局部变量必须加final
2018-09-27 16:24:06我们都知道方法中的匿名/局部内部类是能够访问同一个方法中的局部变量的,但是为什么局部变量要加上一个final呢? 首先我们来研究一下变量生命周期的问题,局部变量的生命周期是当该方法被调用时在栈中被创建,当...我们都知道方法中的匿名/局部内部类是能够访问同一个方法中的局部变量的,但是为什么局部变量要加上一个final呢?
首先我们来研究一下变量生命周期的问题,局部变量的生命周期是当该方法被调用时在栈中被创建,当方法调用结束时(执行完毕),退栈,这些局部变量就会死亡。但是内部类对象是创建在堆中的,其生命周期跟其它类一样,只有当jvm用可达性分析法发现这个对象通过GCRoots节点已经不可达,然后进行gc才会死亡。
所以完全有可能存在的一个现象就是一个方法已经调用结束(局部变量已死亡),但该内部类的对象仍然活着,也就是说内部类创建的对象的生命期会超过局部变量,这就会出现内部类的对象要访问局部变量时访问失败,而java为了保证这种情况不会发生,就用了一种折中的方案:内部类要访问局部变量,局部变量必须加final,那为什么局部变量定义成final就可以了呢?
然后我们再来看final这个关键字修饰变量的特点:当final修饰一个基本数据类型的变量时,这个基本类型的变量在初始化的时候就应该赋值,并且初始化完成之后其值就不能再发生改变了;当final修饰一个引用类型的变量时,这个引用类型的变量在初始化的时候就应该赋值并且之后不能再发生改变,但是引用类型的变量指向的对象的堆内存的值是可以改变的。
基于final修饰变量的以上两个特点,java就把局部内部类对象要访问的final型局部变量,复制过来变成该内部类对象中的一个成员变量,这样即使栈中局部变量(含final)已死亡,但由于它是final的,其值是不会发生改变的,因而内部类对象在局部变量死亡后,照样可以访问自己内部维护的一个值跟局部变量一样的成员变量,从而解决这个问题。
ps:java8中匿名/局部内部类访问局部变量时,局部变量已经可以不用加final了,但其实这个局部变量还是final的,只不过不用显式的加上而已,推测可能是编译机制发生了改变。
-
局部内部类访问局部变量时,变量必须用final修饰
2018-10-24 10:15:02就会随之销毁,但是我的内部类对象可能仍然还存在的(当不在被使用才会被垃圾回收器回收)这时在内部类中访问了局部变量x,但此时的x已经被销毁,内部类访问了一个并不会存在的变量,这就形成了一个矛盾。...直接看例子:
public class Test{ public void play() { int x=4; class InTest{ public void f() { System.out.println(x); } } new InTest().f(); } public static void main(String[] args) { Test t=new Test(); t.play(); } }
此时的局部内部类(定义在方法中的内部类)InTest中的f()访问了外部类中的局部变量x。这里x并没有用final修饰(1.8之后java隐式的将x修饰为final)如果你添加一个x=8,这里就会报错。
为什么要用final修饰
主要原因还是生命周期:当我的t.play()出栈后,play中的局部变量
就会随之销毁,但是我的内部类对象可能仍然还存在的(当不在被使用才会被垃圾回收器回收)这时在内部类中访问了局部变量x,但此时的x已经被销毁,内部类访问了一个并不会存在的变量,这就形成了一个矛盾。根本原因就是:内部类的生命周期比局部变量的长其实如果我们编译Test.java文件发现会出现两个class文件,Test.class和Test$InTest.class文件,java会将Test中的局部变量x复制一份到TestInTest.class中当做是内部类的成员常量。这样我们访问的其实就是复制的那个成员常量。
如何保证数据的一致性:当我们修改局部变量的时候如何保证被复制出来的变量也会同步一致:用final修饰。这样只要这个局部变量进栈初始化的时候就是一个常量。在生命周期内不能被改变,这里注意生命周期。这样就保证了内部类的成员变量和方法的局部变量的一致性。
public void play(final int a){ class InTest{ public void f(){ System.out.println(a); } } new InTest().f(); } public static void main(String[] args) { Test t=new Test(); t.play(6); t.play(7); } }
这样是可以的,因为局部变量a的生命周期是play()方法,随着方法的出栈局部常量也会随之销毁。下一次在进栈的时候又会重新初始化常量的值。
参考:https://blog.csdn.net/sf_climber/article/details/78326984
-
java:面向对象-局部内部类访问局部变量的问题
2018-09-27 16:34:12* 局部内部类访问局部变量必须用final修饰* 局部内部类在访问他所在方法中的局部变量必须用final修饰,为什么? 因为当调用这个方法时,局部变量如果没有用final修饰,他的生命周期和方法的生命周期是一样的,当方法弹栈,...* 局部内部类访问局部变量必须用final修饰
* 局部内部类在访问他所在方法中的局部变量必须用final修饰,为什么?
因为当调用这个方法时,局部变量如果没有用final修饰,他的生命周期和方法的生命周期是一样的,当方法弹栈,这个局部变量也会消失,那么如果局部内部类对象还没有马上消失想用这个局部变量,就没有了,如果用final修饰会在类加载的时候进入常量池,即使方法弹栈,常量池的常量还在,也可以继续使用1.8之前的版本是需要加final,1.8之后不用加也可以使用。
public class Demo2_InnerClass { public static void main(String[]args){ Outher o=new Outher(); o.method(); } } class Outher{ public void method(){ int num=10; class Inner{ public void print(){ System.out.println("局部内部类成员方法"); System.out.println("访问局部变量需要设置为final:"+num); } } Inner i=new Inner();//在方法中创建Inner对象 i.print(); } /* public void run(){//局部内部类,只能在其所在的方法中访问 Inner i=new Inner(); i.print(); }*/ }
-
为什么java内部类访问局部变量必须声明为final?
2018-01-20 05:19:35编程时,在线程中使用局部变量时候经常编译器会提示:局部变量必须声明为final [java] view plain copy package test; public class ThreadTest { public void ... -
内部类之局部内部类只能访问final的局部变量
2020-12-15 19:57:591.首先来了解一下局部内部类是如何访问局部变量的 Person类是外部类,LoInClassIntf是接口,localInClassRe是Person类的成员方法,且返回值类型为LoInClassIntf; 方法内定义了一个局部内部类LoInnerClass,该内部... -
Java 局部内部类访问局部变量必须加final关键字
2016-02-01 21:45:15这里说的事局部内部类,不是普通静态内部类和非静态内部类,因为他们不能访问方法体内的局部变量。 java要求所有被局部内部类访问的局部变量都是用final修饰是因为:对于普通局部变量他的作用域就是该方法内,当... -
Java进阶——Java 局部内部类访问局部变量为什么必须加final关键字
2018-10-16 20:33:50Java 局部内部类访问局部变量为什么必须加final关键字 疑问 在Java中,局部内部类如果调用了方法中的变量,那么该变量必须申明为final类型,如果不申明,则编译就会出错。 这里的内部类指的是方法内部类或匿名内部... -
匿名内部类访问外部类方法中的局部变量
2019-09-04 16:13:16这里所说的“匿名内部类”主要是指在其外部类的成员方法内定义,同时完成实例化的类,若其访问该成员方法中的局部变量,局部变量必须要被final修饰。 原因是编译程序实现上的困难:内部类对象的生命周期会超过局部... -
JDK8之前,匿名内部类访问的局部变量为什么必须要用final修饰
2018-08-15 20:17:51} } 也就是说匿名内部类之所以可以访问局部变量,是因为在底层将这个局部变量的值传入到了匿名内部类中,并且以匿名内部类的成员变量的形式存在,这个值的传递过程是通过匿名内部类的构造器完成的。 那么问题又... -
java中内部类访问局部变量为什么要定义局部变量为final
2016-05-22 10:16:05因为方法内定义的变量是局部变量,离开该方法,变量就失去了作用,也就会自动被消除,而内部类却不会离开它所在方法就失去作用,它有更广的生命周期,下面通过一个实例加以说明: 如例中所示,在外部类Outer中声明了... -
局部内部类访问局部变量细节
2015-09-13 21:12:20class People //file InnerClassTest.java { private int a = 21; public void method() { String go = "running ... //局部变量 class Hand //局部内部类 { public void show() { System.out.print -
局部内部类 局部内部类访问局部变量必须用final修饰
2017-07-15 22:25:56局部内部类访问局部变量的注意事项? A:局部内部类访问局部变量必须用final修饰 B:为什么呢? 局部变量是随着方法的调用而调用,随着调用完毕而消失。 而堆内存的内容并不会立即消失。所以,我们加final... -
Java 方法的内部类访问 方法的局部变量
2017-08-11 10:30:40在Java中 方法的内部类可以访问方法的局部变量 但必须用final修饰 原因 一, 当方法被调用运行完毕之后,局部变量就已消亡了。但内部类对象可能还存在, 直到没有被引用时才会消亡。此时就会出现一种情况,就是... -
Java 匿名内部类调用局部变量
2018-04-16 17:30:02Java 8 之前,匿名内部类中使用 局部变量,需要强制使用 final 修饰 Java 8 开始匿名内部类使用的外部变量不再被强制用final修饰。 外部变量要么是final的;要么自初始化后值不会被改变 这两种都是可以在匿名... -
Java匿名内部类访问外部类的局部变量
2017-07-20 19:18:47Java匿名内部类访问外部类的局部变量,那么这个局部变量需要用final修饰吗? 为什么我的测试没有用final却可以? -
内部类访问局部变量为什么要加final
2015-07-04 09:21:32在内部类中访问局部变量,编译器实际上会为该内部类创建一个成员变量, 以及带有参数的构造方法,然后将该变量传入构造方法,也就是说外面的 变量和类里面的变量就是名字相同而已,此时你无论修改哪一个都对另外 ... -
为什么从内部类访问局部变量,需要被声明为最终类型?
2017-03-28 16:01:08首先要明白: 一个完整的Java程序运行过程会涉及以下内存区域: 寄存器:JVM内部虚拟寄存器,存取速度... 栈:保存局部变量的值,包括:a.用来保存基本数据类型的值;b.保存类的实例,即堆区对象的引用(指针 -
关于java方法中的局部匿名内部类调用局部变量的问题
2019-01-15 23:49:45大家都知道,java的规范中是不允许局部匿名内部类来调用非final的类型局部变量的,这点并没什么好说的毕竟是规范嘛。我们要无条件的遵守。 问题是官方的文档中还有一个词与之先关,“与final”相同效果的变量。之前... -
java中内部类访问局部变量的时候,为什么变量必须加上final修饰
2015-11-15 21:30:37这里的局部变量就是在类方法中的变量,能访问方法中变量的类当然也是局部内部类了。 我们都知道,局部变量在所处的函数执行完之后就释放了,但是内部类对象如果还有引用指向的话它是还存在的。例如下面的代码: ... -
JAVA中匿名内部类访问的局部变量为什么要用final修饰?
2018-07-17 15:40:08局部内部类:定义在方法中的类 //测试类 public class testInnerClass { public static void main(String[] args) { Outerr o = new Outerr(); o.method(); } } class Outerr { public void method() { ... -
JDK1.8之后匿名内部类访问方法中的局部变量不用加final修饰
2018-11-12 20:45:32JDK1.8之后匿名内部类访问方法中的局部变量不用加final修饰 今天在学习ThreadLocal类,在一个方法中写了一个匿名内部类,然后使用方法中的局部变量,发现不用加final修饰变量,即可使用,百度了一下,原来是jdk1.8的... -
jdk7之前,匿名内部类访问局部变量加final修饰的问题(综合两种说法)
2017-12-27 14:03:55当使用匿名内部类的时候,如果匿名内部类需要访问匿名内部类所在方法中的局部变量的时候,必须给局部变量加final进行修饰。不加final修饰的局部变量,匿名内部类是访问不到的。这是为什么呢?网上有两种说法,第一种... -
关于内部类的问题: 局部内部类访问外部类的局部变量问题(原理性问题)
2019-06-17 14:17:31关于内部类的问题: 局部内部类访问外部类的局部变量问题 编程时,在线程中使用局部变量时候经常编译器会提示:局部变量必须声明为final [java] view plain copy package test; public class ThreadTest { ... -
局部内部类访问外部类的局部变量
2017-03-13 15:28:16在书上看到这样一段话:如果局部内部类要访问外部类的局部变量,则此变量必须是final修饰的,否则不能访问。说是为了提高局部变量的生命周期,可不可以说的通俗一些? -
内部类访问局部变量时,为什么需要加final关键字
2015-08-03 15:30:44但实际编译的时候,内部类编译成Outer.Inner,这说明内部类所处的位置和外部类中的方法处在同一个等级上,外部类中的方法中的变量或参数只是方法的局部变量,这些变量或参数的作用域只在这个方法内部有效。... -
深入理解为什么Java中方法内定义的内部类可以访问方法中的局部变量
2018-06-25 09:43:01定义在方法中的内部类在平时写代码的过程中, 我们经常会写类似下面的代码段:[java] view plain copypublic class Test { public static void main(String[] args) { final int count = 0;... -
匿名内部类访问的局部变量为什么必须要用final修饰
2019-12-03 14:29:01也就是说匿名内部类之所以可以访问局部变量,是因为在底层将这个局部变量的值传入到了匿名内部类中,并且以匿名内部类的成员变量的形式存在,这个值的传递过程是通过匿名内部类的构造器完成的。 那么问题又来了,... -
匿名内部类访问的局部变量为什么必须为final
2018-04-19 17:55:24而且Javascript的语法允许内部函数function(x)访问外部函数Add(y)的局部变量。满足这三个条件,所以这个时候,外部函数Add(y)对内部函数function(x)构成了闭包。 闭包的结构,如果用 λ演算 表达式来写,就是多参数...