最近一直纠结于局部内部类访问局部变量为啥一定要有final修饰的问题,论坛上的回答大多是说局部内部类的生命周期是随方法的消失而消失的,需要加final来延长生命周期,这里有一个问题,内部类对于JVM仅仅是是一个类而已,不会像人这么聪明知道内部类和外部类的关系,那为啥其他非内部类就不能像内部类一样访问定义在局部的变量呢?(实际上,此变量除了成员方法就没法访问了,就是说连外部类的其他局部都无法访问或是提供访问方法)但是出于小心,我还是做了测试,测试的方法时将方法用static修饰,这样方法的生命周期就延长了,也就是延长了变量生命周期,但是还是需要有final修饰,因此重新上网搜寻答案,得到了一个比较满意的答案,就是JVM会隐藏地将变量的一个副本作为内部类构造函数的一个实参传递给内部类,是内部类有一个和此变量类型和值都相同的字段,可惜的是,正如前面所讲,内部类是不能访问到外部类局部变量的,为了保持此变量在内部类的对象和外部类对象的一致性,只有将其设为常量,也就是加final修饰,
为了验证,我用反射的方式得到了内部类的字段类型和其对应的值,进一步证实了此说法。以下是测试代码:
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
class Outer{
public static void test(){
final Integer i=5;
class Inner{
public void show(){
System.out.println(i);
}
}
Inner inner=new Inner();
Class clazz=inner.getClass();
Field[] fields=clazz.getDeclaredFields();
for(Field field:fields){
System.out.println(field);
field.setAccessible(true);
try {
System.out.println(field.get(inner));
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public class InnerClassTest {
public static void main(String[] args) {
Outer outer=new Outer();
outer.test();
}
}
测试的结果为:
private final java.lang.Integer test.collection.Outer$1Inner.val$i
5
说明内部类的确有一个Integer类型的常量,且值和所访问方法上的变量一致,应该不是巧合,本可以通过反编译命令得到内部类的源码,限于笔者能力,未做此方面的测试。
|