黑马程序员技术交流社区

标题: 问题已经解决内部类定义在局部时的疑问? [打印本页]

作者: 郑彬    时间: 2012-8-14 18:00
标题: 问题已经解决内部类定义在局部时的疑问?
本帖最后由 郑彬 于 2012-8-15 14:32 编辑

内部类定义在局部时:
1.不可以被成员修饰符修饰
2,可以直接访问外部类中的成员,因为还持有外部类中的引用。但是不可以访问它所在的局部中的变量。只能访问被final修饰的局部变量。
求解释?为什么?
作者: 杨彪    时间: 2012-8-14 18:12
首先的了解什么是内部类,还有就是成员变量和局部变量的区别
        (1)把一个类定义在某个类中的,这个类就被称为内部类,内置类,嵌套类。
        (2)访问形式:
                A:内部类可以直接访问外部类中的成员。
                B:外部类要想访问内部类的成员,必须创建对象访问。
        (3)什么使用时候内部类呢?
                假如有A类和B类,A类想直接访问B类的成员,B类访问A类成员的时候,
                需要创建对象访问,这个时候,就可以把A类定义为B类的内部类。
        (4)内部类的位置
                A:成员位置
                        **可以被private修饰(Body,Heart)
                        **可以被static修饰。(它访问的外部类的成员必须是静态的)

                class Outer
                {
                        int num = 10;

                        class Inner
                        {
                                public void show()
                                {
                                        sop(num);
                                }
                        }       

                        public void method()
                        {
                                Inner i = new Inner();
                                i.show();
                        }
                }

                注意:
                        如果测试类中想直接访问内部类,格式如下
                        外部类名.内部类名 对象名 = 外部类对象.内部类对象;
                        Outer.Inner oi = new Outer().new Inner();

                        假如内部类使用static修饰的,在测试类中使用,格式如下
                        外部类名.内部类名 对象名 = new 外部类.内部类();
                        Outer.Inner oi = new Outer.Inner();
               
                B:局部位置
                        **可以直接访问外部类中的成员,也可以直接访问局部成员,但是
                          局部成员要用final修饰。
               
                class Outer
                {
                        int num = 10;

                        public void method()
                        {
                                int num2 = 20;
                                final int num3 = 30;

                                class Inner
                                {
                                        public void show()
                                        {
                                                sop(num3);
                                        }
                                }

                                Inner i = new Inner();
                                i.show();
                        }
                }

                注意:
                        局部内部类不能用private和static修饰。


作者: 黎健东    时间: 2012-8-14 18:14
如果局部变量是非final修饰的,则无法访问;如果局部变量是final修饰的,则可以访问。

/*
不可以被成员修饰符修饰
只有抽象的或者filnal修饰的内部类才能用成员修饰符修饰
*可以直接访问外部类中的成员,因为还持有外部类中的引用。但是不可以访问它所在的局部中的变量。只能访问被final修饰的局部变量
* 理由如下:
* 因为 ,类的生命周期是从被new了之后才开始的,局部变量的生命周期从这个类开始而产生,随着这个类结束而死亡
* 假如下面inner中的y是能够被改写的,则当inner类结束了y就死亡了,method这个方法后面就不能再用y了。
* 而又因为method中的y的生命周期是从method开始而诞生,到method结束而消亡
* y在离开inner之后就死亡了,推出矛盾
* 所以,inner不能访问method中的y
*
* 如果需要访问,则可以像x限定为final,编译器会将x拷贝一份到到inner中
* 由于final的性质,该x只能被访问不能被修改
* inner可以把它当做自己的成员属性访问
* inner结束之后,死亡的是inner中的x
* method中的x持续到method结束才死亡

public class Test001_InnerClass {
        public static void main(String[] args){
                method();
        }

        private static void method() {
                final int x = 0;
//                int y = 1;
                class inner{
                        //存在以下的一个拷贝
                        //final int x = 0;
                        //不能访问
//                        y = 2;
                        public inner() {
                                System.out.println(x);
                                //下面不能访问
//                                System.out.println(y);
                        }
                }
                new inner();
        }
}

class outer{

        void in(){
                new inner();
        }
       
        class inner{
               
        }
}


作者: 左建飞    时间: 2012-8-14 18:15
实际开发不知道这个原因可能出现错误。
    final修饰后,编译器是这样处理内部类的,如果这个外部局部变量是常量,则在内部类代码中直接用这个常量。如果是类的实例,则编译器将产生一个内部类的构造参数,将这个final变量传到内部类里,这样即使外部局部变量无效了,还可以使用。
    内部类并不是直接调用方法传进来的参数,而是内部类将传进来的参数通过自己的构造器备份到了自己的内部,自己内部的方法调用的实际是自己的属性而不是外部类方法的参数。
   这样理解就很容易得出为什么要用final了,因为两者从外表看起来是同一个东西,实际上却不是这样,如果内部类改掉了这些参数的值也不可能影响到原参数,然而这样却失去了参数的一致性,因为从编程人员的角度来看他们是同一个东西,如果编程人员在程序设计的时候在内部类中改掉参数的值,但是外部调用的时候又发现值其实没有被改掉,这就让人非常的难以理解和接受,为了避免这种尴尬的问题存在,所以编译器设计人员把内部类能够使用的参数设定为必须是 final来规避这种莫名其妙错误的存在 。
作者: 方志亮    时间: 2012-8-14 18:20
因为方法中的代码是由上而下顺序执行的,方法运行结束后,局部变量就被销毁,内部类的生命周期可能会比局部变量的生命周期长;看下面的代码,方法中的内部类 Inner.class 调用方法中的局部变量 x ,正常调用的时候内部类能够调用到方法中的局部变量,并将内部类对象 inner 返回,正常调用结束后,如果方法中的局部变量 x 没有被 final 关键字修饰,x 则会被销毁,我们再通过反射的方式去调用 x 的时候则会发现找不到变量 x ,如果局部变量 x 被 final 关键字修饰后,则 x 在方法运行结束后不会被销毁,而是常驻在内存中直到 JVM 退出,这样再通过反射调用的时候依然可以找到 x 。
*/

import java.lang.reflect.Method;

public class InnerClassCallLocalVar {

    @SuppressWarnings({ "unchecked", "rawtypes" })
    public static void main(String[] args) throws Exception {
        Outer outer = new Outer();                                // 正常调用
        Object object = outer.outerfun();
        
        Class clazz = object.getClass();                        // 反射调用
        Method method = clazz.getMethod("innerfun");
        method.invoke(object);
    }
}

class Outer {
    public Object outerfun() {
        final int x = 5;
        class Inner {
            public void innerfun() {
                System.out.println(x);
            }
        }
        Inner inner = new Inner();
        inner.innerfun();
        return inner;
    }
}



作者: 郑彬    时间: 2012-8-15 14:32
问题已经解决。




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2