嵌套和内部类

术语和分类

Java 语言规范(JLS)按如下方式对不同类型的 Java 类进行分类:

一个顶层类是一类,是不是一个嵌套类。

一个嵌套类是任何类,其声明另一个类或接口的主体内发生。

一个内部类是没有明确或隐含声明为静态的嵌套类。

内部类可以是非静态成员类本地类匿名类。接口的成员类是隐式静态的,因此永远不会被视为内部类。

在实践中,程序员引用包含内部类作为外部类的顶级类。此外,还有一种倾向,即使用嵌套类仅引用(显式或隐式)静态嵌套类。

请注意,匿名内部类和 lambdas 之间存在密切关系,但 lambdas 是类。

语义差异

  • 顶级类是基础案例。它们对程序的其他部分是可见的,受基于访问修饰符语义的正常可见性规则的约束。如果是非抽象的,则可以通过任何基于访问修饰符可见相关构造函数的代码来实例化它们。

  • 静态嵌套类遵循与顶级类相同的访问和实例化规则,但有两个例外:

    • 嵌套类可以声明为 private,这使得它在封闭的顶级类之外无法访问。
    • 嵌套类可以访问封闭顶级类的 private 成员及其所有测试类。

    这使得静态嵌套类在需要在紧密抽象边界内表示多个实体类型时非常有用; 例如,当嵌套类用于隐藏实现细节时。

  • 内部类添加了访问在封闭范围中声明的非静态变量的功能:

    • 非静态成员类可以引用实例变量。
    • 本地类(在方法中声明)也可以引用方法的局部变量,前提是它们是 final。 (对于 Java 8 及更高版本,它们可以是最终的。)
    • 匿名内部类可以在类或方法中声明,并且可以根据相同的规则访问变量。

    内部类实例可以引用封闭类实例中的变量这一事实对实例化有影响。具体而言,当创建内部类的实例时,必须隐式或显式地提供封闭实例。