每个内部类都需要一个封闭的实例吗?

2022-09-01 07:55:10

术语内部类通常表示“需要封闭实例的嵌套类”。但是,JLS声明如下:

8.1.3. 内部类和封闭实例

[...]

内部类包括本地类 (§14.3)、匿名类 (§15.9.5) 和非静态成员类 (§8.5)。

[...]

其声明发生在静态上下文中的内部类的实例没有词法封闭实例。

15.9.5. 匿名类声明

[...]

匿名类始终是内部类 (§8.1.3);它永远不会(§8.1.1,§8.5.1)。static

众所周知,匿名类可以在静态上下文中声明:

class A {
  int t() { return 1; }
  static A a =  new A() { int t() { return 2; } };
}

为了凄美地描述它,

new A() {} 是一个没有封闭实例的嵌套类,在静态上下文中定义,但它不是静态嵌套类,而是一个内部类。

我们是否都在日常使用中为这些术语赋予不适当的含义?

作为相关的兴趣点,此历史规范文档将术语顶级定义为与内部相反:

作为类成员的类和作为包成员的类都称为顶级类。它们与内部类的不同之处在于,顶级类只能直接使用自己的实例变量。static

而在通常的用法中,顶级被认为是嵌套的反面。


答案 1

从规范的角度来看,问题中列出的区别是完全有意义的:

  • 内部类具有对其施加的限制,这些限制与封闭实例的问题无关(例如,它可能没有静态成员);

  • 静态嵌套类的概念基本上只是关于命名空间;这些类可能理所当然地被称为顶级类,以及我们通常假设的顶级类。

碰巧的是,从嵌套类声明中删除会同时执行两件独立的事情:static

  1. 它使类需要一个封闭的实例;
  2. 它使类内部

我们很少认为内在会带来限制;我们只关注封闭的实例问题,这更加明显。但是,从规范的角度来看,这些限制是一个至关重要的问题。

我们缺少的是需要封闭实例的类的术语。JLS没有定义这样的术语,因此我们已经(似乎没有意识到)劫持了一个相关的,但实际上本质上是不同的术语来表示。


答案 2

好吧,在您的案例中,匿名类不是也有一个封闭的实例吗?它是静态的引用,而不是匿名类的实例。考虑:

class A {
   int t() { return 1; }
   static A a = new A() { { System.out.println(t()); } };
}