Java内部类问题

Java内部类的作用:
1)可以隐藏代码中的细节:一般的类智能为public,内部类可以为private、protected,实现隐藏
2)方便调用外部类的成员变量:内部类拥有外部类的this指针
3)便于实现多重继承:

class M {}
class N {}

class P {
    class P1 extends M{}
    class P2 extends N{}
} 

一、内部类生成class文件情况:

public class A {

    class C {
        class G{}
    }

    static class D {}

    void a () {
        // 注意:方法中的内部类的class文件格式与别的不同
        class E{}
    }

    interface F {}

    abstract class H {}
}

class B {}

生成的class文件:
Java内部类问题_第1张图片

二、内部类问题:

public class A {
    class B {}

    static class C {}
    // 在静态方法中,由于没有this指针,初始化时不能直接使用B的构造函数
    /**== 即构建内部类对象时,需要一个指向其外围类对象的引用,内部类对象会链接到该外部类对象上。所以应当首先创建外部类对象; * 而对于嵌套类(静态内部类),则不需要该引用 ==**/
    public static void a() {
        // 由于B是非static的,访问其需要通过初始化A的实例进行使用
        A aa = new A();
        B bb = aa.new B();

        // 因为C也是静态内部类,所以可以直接用其构造函数
        C cc = new C();
    }

    // 在非静态方法中的初始化较为简单
    public void b() {
        B b = new B();
        C cc = new C();
    }
}

// 注意在外部类中的初始化方法与A类中的不同
class E {
    public void m() {
        A a = new A();
        // 声明需要完整的OutClass.InnerClass格式
        A.B b = a.new B();  // 非静态类的初始化
        A.C c = new A.C();  // 静态类的初始化
    }
}

构建内部类对象时,需要一个指向其外围类对象的引用,内部类对象会链接到该外部类对象上,所以应当首先创建外部类对象;
而对于嵌套类(静态内部类),则不需要该引用。
而因为内部类对象保存了对外部类对象的引用,故可以访问外部类中的所有成员变量及方法;

三、局部内部类:
局部内部类:定义在方法或者任意作用域中的类;它只是方法的一部分,而不是外部类的一部分。
1)局部内部类的生命周期问题:局部内部类的生命周期并不会随着方法的结束而结束;

public class A {
    class B {
        public void printData() {
            System.out.println("B");
        }
    }

    public B a() {
        class C extends B{
            @Override
            public void printData() {
                System.out.println("C");
            }
        }
        // 这里实例化C对象,并向上转化为其父类B
        return new C();
    }

    public void printData() {
        a().printData();
    }

    public static void main(String[] args) {
        new A().printData();
    }
}

最后输出的结果为“C”,可以看到C的生命周期并未结束。
2)使用外部变量需用final进行修饰的问题:

public class A {
    class B {
        public void printData() {
            System.out.println("B");
        }
    }

    String outerClass_data = "outerClass_data";

    public B a(final String parameter_data) {
        final String outerMethod_data = "outerMethod_data";
        class C extends B{
            @Override
            public void printData() {
                /** 可以看到因为生命周期的原因,parameter_data与outerMethod_data的生命周期较短; * 故需要使用final对其进行修饰 **/
                System.out.println(outerClass_data);
                System.out.println(outerMethod_data);
                System.out.println(parameter_data);
            }
        }
        // 这里实例化C对象,并向上转化为其父类B
        return new C();
    }

    public void printData() {
        String data = "data";
        a(data).printData();
    }

    public static void main(String[] args) {
        new A().printData();
    }
}

该外部变量必须使用final进行修饰是因为生命周期的原因,因为方法内部变量,或者形参,其生命周期是与方法相同的;而前面也提到局部内部类的生命周期并不会因为方法的结束而结束;即方法局部变量与局部内部类的生命周期不同;当方法结束后,就会出现局部内部类非法引用已经销毁的局部变量的情况;
因而虚拟机采用的做法是使用final进行修饰该变量,在编译局部内部类时,会在局部内部类内部生成一个该final变量的拷贝,从而解决生命周期的问题。

四、匿名内部类 实现继承:
1)匿名内部类的定义

public class A {
    class B {
        public void printData() {
            System.out.println("B");
        }
    }

    String outerClass_data = "outerClass_data";

    public B a(final String parameter_data) {
        final String outerMethod_data = "outerMethod_data";

        // 定义一个匿名内部类
        return new B() {
            @Override
            public void printData() {
                /** 可以看到因为生命周期的原因,parameter_data与outerMethod_data的生命周期较短; * 故需要使用final对其进行修饰 **/
                System.out.println(outerClass_data);
                System.out.println(outerMethod_data);
                System.out.println(parameter_data);
            }
        };
    }

    public void printData() {
        String data = "data";
        a(data).printData();
    }

    public static void main(String[] args) {
        new A().printData();
    }
}

其实上面局部内部类的用法可以精简地写成匿名内部类的形式:匿名内部类表示创建一个集成自B的一个匿名类对象,并且通过new表达式将返回的引用自动向上转型为B的引用。
因而局部内部类对final变量的要求对于匿名内部类同样适用;
2)带参数初始化的匿名内部类:

public class A {
    class B {
        public B(int i) {}
        public void printData() {
        }
    }

    public B a() {
        // 定义一个匿名内部类
        return new B(100) {
            @Override
            public void printData() {
            }
        };
    }
}

3)局限性:匿名内部类相对于正常的继承,它可以实现继承类,也可以实现接口;当两个同一时刻只能实现一种;即是是实现接口,也只能实现一个接口;

你可能感兴趣的:(Java内部类问题)