前言:
眼前大家对“可以修饰局部变量”大概比较注重,看官们都需要学习一些“可以修饰局部变量”的相关内容。那么小编在网络上网罗了一些关于“可以修饰局部变量””的相关知识,希望小伙伴们能喜欢,我们一起来了解一下吧!JDK8之前,Java中匿名内部类访问的局部变量必须要加上final关键字,否则编码不通过,JDK8后则不用加,编译器会自动加上final。那为什么匿名内部类访问的局部变量必须要用final修饰呢?
下面以jdk1.7为基础先写一个简单的Demo,如下:
如果num变量不加final则编译不通过,这是什么原因呢,针对这个问题的争论比较多,有2种主流的说法:
一种说法是:当printString方法出栈后,num这个局部变量也会消失,那么如果TestInterface再去调用print()方法时想用num这个局部变量时,num没有了,如果用final修饰会在类加载的时候进入常量池,即使方法出栈,常量池的常量还在,也可以继续使用。
另一种说法是:局部变量是被当成了参数传递给匿名对象的构造器,作为成员变量在堆上存在,至于局部变量销毁就销毁,反正都拷贝了一份,只需要保证这个变量代表的值或地址不变就行了。
这2种说明哪一种比较正确呢,那我们来验证它,毕竟实践是检验真理的唯一标准。
验证
1、在BaseClass编译之后的class目录下,发现在class目录下生成了2个.class文件,很明显BaseClass$1.class是一个内部类的字节码文件。
2、将BaseClass$1.class通过javap -c进行反汇编后结果如下:
3、将BaseClass.class通过javap -c进行反汇编后结果如下:
根据以上反汇编得出的信息,事实上真正的反编译代码应该是下面这样的:
通过以上分析得出:匿名内部类之所以可以访问局部变量,是因为在底层将这个局部变量的值传入到了匿名内部类中,并且以匿名内部类的成员变量的形式存在,这个值的传递过程是通过匿名内部类的构造器完成的。通俗来说就是局部类通过创建私有实例字段来保存局部变量的副本。
那为什么不能引用非final的局部变量呢?
因为如果变量不是final,那么方法中变量的副本可能会更改,而局部类中的副本则不会,因此它们将不同步。局部类通过创建私有实例字段来使用局部变量,该字段保存局部变量值的副本。内部类实际上并没有使用局部变量,而是使用了一个副本。很明显,如果原始值或复制的值发生变化,将会出现一些意想不到的数据同步问题。为了防止这种问题,编译器要求局部类使用的局部变量标记为final,保证内部类的局部变量副本将始终与实际值匹配。
标签: #可以修饰局部变量