您的位置:首页 > 其它

方法中的内部类不能访问方法中的局部变量的 【真正原因】

2014-09-26 14:53 267 查看
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();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: