欢迎访问悦橙教程(wld5.com),关注java教程。悦橙教程  java问答|  每日更新
页面导航 : > > 文章正文

方法中的内部类能不能访问方法中的局部变量,为什么?,,早先也不理解为什么,也是

来源: javaer 分享于  点击 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
相关栏目:

用户点评