Java:私有内部类合成构造函数

shr*_*000 16 java inner-classes

我有Outer一个private Inner班级.

在我的Outer类方法中,我Inner按如下方式实例化该类:

Outer outer = new Outer();
Inner inner = outer.new Inner();
Run Code Online (Sandbox Code Playgroud)

编译器将此代码转换为:

Outer outer = new Outer();
Inner inner = new Inner(outer, null);
Run Code Online (Sandbox Code Playgroud)

使用反射显示Inner该类具有以下合成构造函数:

private Outer$Inner(Outer)
Outer$Inner(Outer,Outer$Inner)
Run Code Online (Sandbox Code Playgroud)

由于Inner类是private,编译器将该private构造函数添加到它,因此没有人可以实例化该类.但显然Outer该类应该能够实例化它,因此编译器会添加其他包私有构造函数,后者又调用私有构造函数.此外,由于package-private构造函数$在其名称中具有该名称,因此普通Java代码无法调用它.

问题:为什么要合成一个私有和一个包私有构造函数?为什么不合成package-private构造函数并完成呢?

sbr*_*ges 13

如果你写代码,

public class Outer {
      private class Inner {}
}
Run Code Online (Sandbox Code Playgroud)

您会注意到只有一个构造函数 private Outer$Inner(Outer)

这个构造函数是JLS的8.8.9节所要求的,它表示如果没有定义构造函数,则必须生成默认构造函数,在这种情况下,默认构造函数必须是私有的,

在类类型中,如果类被声明为public,则默认构造函数被隐式赋予访问修饰符public(§6.6); 如果该类被声明为protected,则默认构造函数被隐式赋予访问修饰符protected(§6.6); 如果该类被声明为private,则默认构造函数被隐式赋予访问修饰符private(§6.6); 否则,默认构造函数具有无访问修饰符隐含的默认访问权限.

但是,当您使用代码来实例化Inner inside Outer的实例时,

public class Outer {
    private class Inner {}
        public String foo() {
            return new Inner().toString(); 
        }
}
Run Code Online (Sandbox Code Playgroud)

编译器必须生成一个Outer可以合法调用的构造函数(你不能合法地调用私有默认构造函数,因为它是私有的).因此编译器必须生成一个新的合成构造函数.根据JLS第13.1节,新构造函数必须是合成

除了默认构造函数和类初始化方法之外,编译器引入的任何在源代码中没有相应构造的构造都必须标记为合成构造.

第二个构造函数在源代码中没有相应的构造,因此这个新的构造函数必须是合成的.仍然必须生成第一个私有构造函数,因为JLS需要私有默认构造函数.