方法中的内部类能不能访问方法中的局部变量,为什么?,,早先也不理解为什么,也是
分享于 点击 25575 次 点评:282
方法中的内部类能不能访问方法中的局部变量,为什么?,,早先也不理解为什么,也是
早先也不理解为什么,也是跟百度上的结果一样随大流,甚至这么久都还以为那些说法是正确的,最近比较热衷于反射,所以写了这个代码来解释为什么会这样。
package question6;import java.lang.reflect.Field;/* * 方法中的内部类能不能访问方法中的局部变量,为什么? */public class NoFinalFieldCnnotUsedInner{ public static void main(String[] args) { Outer outer = new Outer(); SuperInner inner = outer.outer(); inner.inner(); }}/* 定义一个局部内部类的上层接口,用以允许返回局部内部类实例 */interface SuperInner{ void inner();}/* 定义一个外部类,包括一个outer方法,用以返回局部内部类实例 */class Outer{ int y = 0; //out方法将返回inner实例 SuperInner outer() { //假设我们这里x可以被inner访问,那么outer函数返回之后 //x已经被销毁,inner对象就无法访问x //换句话说就是Inner对象的生存周期超出了x的边界,而能保证 //生存周期一致的情况只有inner对象自己的成员,所以通过在 //inner里边复制一个x来保存这个局部变量x的值以达到目的 //就像val$x一样 //但这种办法有个致命点,如果在inner里对val$x进行赋值操作 //外边的x并不会被改变,所以为了保证两个对象的一致性,该变量 //x以及其复制变量val$x必须为终态的,也就是final,不能再次 //赋值 //反编译inner可以证明以上结论,在字节码里// question6.Outer$1Inner(question6.Outer, java.lang.String) //这是构造方法,传outer不奇怪,内部类都需要外部类的引用指针 //这个String字符串就值得思考了 //4 getfield val$y //在inner方法中可以看到这个字节码,是val$y 而不是y int x = 4; final String y = new String("asd"); class Inner implements SuperInner {// int val$x = 4; public void inner() { try { //这里通过反射,可以发现证明此y非彼y,因为我们并没有 //在inner里定义val$y变量,而我们却可以拿得到,没异常 //而我们改的是val$y的值为qqq,下边的syso(y)居然会输出 //qqq,结论可以证实 //通过代码也可以看出来,这个val$y肯定是private的,并且 //他也是final的 Field field = getClass().getDeclaredField("val$y"); field.setAccessible(true); System.out.println(field.get(Inner.this)); field.set(Inner.this, "qqq"); } catch (Exception e) { e.printStackTrace(); }// System.out.println(x);本行编译报错,提示局部内部类访问必须是终态的 System.out.println(y);//输出y的值 } } //当inner实例被返回时,x将被销毁 return new Inner(); }}//该片段来自于http://byrx.net
用户点评