内部类笔记

76 阅读2分钟

内部类

内部类分类

分为静态内部类和非静态内部类,非静态内部类中根据内部类的声明位置又分成员内部类、方法内部类、匿名内部类;

可以用内部类做什么:

  • 修复类只能单继承的缺陷,在类中可以通过声明多个成员内部类来分别继承对应是类;
  • 内部类可以被private、protected等修饰,所以可以通过此方式来向上转型时的代码隐藏;
    public class Out{
        private class Inner exetend Facade{
            public void test() {
                sout("test me");
            }
        }
        public Facade innerFacade() {
            return new Inner;
        }
    }
    
  • 匿名内部类可以避免写一大串代码

内部类可能造成内存泄漏:

如果当内部类的引用被外部类以外的其他类引用时,就会造成内部类和外部类无法被GC回收的情况,即使外部类没有被引用,因为内部类持有指向外部类的引用)



public class ClassOuter {

    Object object = new Object() {
        public void finalize() {
            System.out.println("inner Free the occupied memory...");
        }
    };

    public void finalize() {
        System.out.println("Outer Free the occupied memory...");
    }
}

public class TestInnerClass {
    public static void main(String[] args) {
        try {
            Test();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private static void Test() throws InterruptedException {
        System.out.println("Start of program.");

        ClassOuter outer = new ClassOuter();
        Object object = outer.object;
        outer = null;

        System.out.println("Execute GC");
        System.gc();

        Thread.sleep(3000);
        System.out.println("End of program.");
    }
}

outer强引用被置为null,理论上会被回收但是并没有被回收就是因为内部类对象依然被持有,未被释放。导致泄漏。

为什么局部变量需要final修饰呢

原因是:因为局部变量和匿名内部类的生命周期不同。 内部类是加载在heap中的,而局部变量是在stack中的,当方法结束局部变量退栈导致内部类访问不到局部变量,所以需要保留一份备份到heap中。

变量访问限制

静态内部类可以访问外部类的静态变量,不可以访问非静态变量; 非静态内部类可以访问外部类的静态和非静态变量;

  • 内部类之所以可以访问外部类的变量是因为内部类初始化的时候就默认携带了一个外部类的引用;

加载

加载外部类并不意味着加载内部类,因为他们不是is-a 的关系; 内部类需要单独声明加载

内部类和外部类关系

内部类和外部类并不是 is-a 的关系,因为经过编译之后内部类和外部类会分别生成两个class文件: out.class 、out#inner.class

参考文章