警告#1:实际上这是一个潜在的两部分:首先,私有内部类的构造函数是否具有形式参数?如果是,为什么JLS拒绝呢?如果没有,怎么/为什么不呢?
注意事项2: 此问题不用于推测。 我仅在寻找 权威 答案。
默认构造函数在JLS 8.8.9中定义,该声明(部分说明):
除了在 非私有 内部成员类中之外,默认构造函数没有形式参数,在默认情况下,默认构造函数隐式声明一个表示该类的立即封闭实例的形式参数(第8.8.1节,第15.9.2节,第15.9.3节) )。
(添加了重点)
“非私有”位对我来说似乎很奇怪:为了让内部类访问其封闭类中定义的字段,它需要对该实例的引用。无论内部类是否为私有,都应相同。
实际上,与规范相反,javac似乎同意我的观点。如果我编译此:
public class Ctors { private class MyInner { } }
…并运行javap -c -private,然后我们看到一个带有单个形式参数的构造函数,用于封闭类的实例:
javap -c -private
$ javap -c -private Ctors\$MyInner Compiled from "Ctors.java" class Ctors$MyInner { final Ctors this$0; private Ctors$MyInner(Ctors); Code: 0: aload_0 1: aload_1 2: putfield #1 // Field this$0:LCtors; 5: aload_0 6: invokespecial #2 // Method java/lang/Object."<init>":()V 9: return }
作为参考,它在Oracle JDK 1.8.0_05上。
因此,JLS说私有内部成员类的默认构造函数没有形式参数,而javac / javap说它有一个。(我对最自然的工作方式的理解也会说,它应该有一种,但值得的。)哪个是对的,为什么JLS专门排除私有内部类?
实现和规范之间有区别。
我认为“除外” JLS声明
… 除了 非私有内部成员类…
措辞不佳。
这意味着, 不需要 编译器隐式声明一个表示该类的立即封闭实例的形式参数…但是 可以 。
为什么非私有内部成员类 需要 隐式形式参数?
从JLS 8.8.1开始:
成员类可能是由与类实例创建表达式的编译器不同的编译器发出的。因此,创建表达式的编译器必须有一种标准方法将引用(表示立即封闭的实例)传递给成员类的构造函数
例如,如果我使用第一个编译器编译此内部类:
package p1; public class Ctors { public class MyInner { } }
如果我想用另一个编译器编译这个子类:
package p2; import p1.Ctors; public class SubCtors { public SubCtors() { new Ctors(); } }
第二个编译器必须能够将默认构造函数与形式参数一起使用。在这种情况下,带有一个SubCtors实例的封闭类的实例。
SubCtors
为什么在非私有内部成员类中 不需要 隐式形式参数?
因为非私有内部成员类始终由编译它的同一编译器访问。如您所示,无论类可见性如何,javac都会生成相同的构造函数,但这不是必需的。另一个编译器实现可以自由选择其他方式。
JLS 8.8.1还有一点,就是同一条线
在用于 本地类(不是在静态上下文中) 或匿名类的类实例创建表达式中,第15.9.2节指定了本地/匿名类的直接封闭实例。本地/匿名类必须由与类实例创建表达式相同的编译器发出。该编译器可以随心所欲地表示立即封闭的实例。 Java编程语言无需在本地/匿名类的构造函数中隐式声明参数。