- 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://www.codesnippet.cn/detail/040920135619.html
来源: http://www.codesnippet.cn/detail/040920135619.html