内部类的原理理解

  对于内部类的概念一直理解的不是很深刻,今天下午看了一下一些大牛的博客,结合《core Java》这本书对于内部类的描写(占了一章的较大的篇幅),将知识点总结如下:

  基础知识:内部类定义在一个类的内部,可以无视私有权限的访问外部类的变量。内部类分为两种:

  1.类中内部类(私有内部类,静态内部类)

  2.方法内内部类(局部内部类,匿名内部类)

  一.类中内部类

  对于类中内部类,对于一个外部类进行编译后,会生成两个文件:1)Outer.class文件,2)Outer$Inner.class文件,内部类是一种编译器现象,与虚拟机无关,编译器会将内部类翻译成用$分割外部类名与内部类名的常规类文件,而虚拟机对此一无所知,这是其一。

  那么内部类是如何访问外部类的私有变量的呢?以下是反射得到的结果:

  

class Outer$Inner {
    public Outer$Inner(Outer);
    final Outer this$0;
}

  可以看出编译器会在内部类中添加一个对于外部类的引用,并且在内部类初始化的时候,将外部类的引用传入,方便调用外部类的变量。但是外部类的私有变量是如何访问的呢?这还是要看外部类的反射结果:(这里假设内部类使用了外部类的私有变量x),以下是外部类的反射结果:

class Outer {
    private int x;
    public Outer(int);
    static int access$0(Outer);
}

  很明显,在编译器检测到内部类需要访问外部类的私有成员变量的时候,会在外部类“动手脚”,即创建一个叫做access$0方法,它将返回作为参数传递给它的对象域x,内部类的方法将调用这个方法,即内部类访问x的时候,实际上是access$0(this$0),这就是内部类能访问外部类成员变量的原因。

  接下来讨论的是静态内部类。

  静态内部类是没有指向外部类的引用this$0的,相对应的也无法访问外部类的非静态成员,除此之外与非静态内部类没有区别。

  二.方法内部类

  对于局部内部类来说,是如何访问方法参数中的变量或者方法定义的变量呢?答案是编译器会自动添加相对应的构造参数。对于一个在方法中声明的内部类进行反射,得到的代码如下:

  

class Outer$Inner {
    Outer$Inner(Outer,int);
    final int val$x;
    final Outer this$0;
}

  注意构造器的int参数和val$x的实例变量。当创建一个对象的时候,x会被传入构造函数,并且最终对于val$x进行初始化,这也是局部内部类中的变量必须为final的原因,所以final关键字的目的就是为了保证内部类和外部函数对变量“认识”的一致性。

  而对于匿名内部类,其不能有构造器,因此取而代之的是将构造器参数传递给超类构造器。

加油
原文地址:https://www.cnblogs.com/hlhdidi/p/5575607.html