Java:私有内部类合成构造函数
我有一个Outer
类,有一个private Inner
类。
在我的Outer
类方法中,我实例化Inner
类,如下所示:
Outer outer = new Outer(); Inner inner = outer.new Inner();
编译器将此代码转换为:
Outer outer = new Outer(); Inner inner = new Inner(outer, null);
使用reflection显示Inner
类具有以下合成构造函数:
private Outer$Inner(Outer) Outer$Inner(Outer,Outer$Inner)
由于Inner
类是private
,编译器会将private
构造函数添加到它,因此没有人可以实例化该类。 但显然Outer
类应该能够实例化它,因此编译器会添加其他包私有构造函数,后者又调用私有构造函数。 此外,由于package-private构造函数在其名称中包含$
,因此普通Java代码无法调用它。
问题:为什么要合成一个私有和一个包私有构造函数? 为什么不合成package-private构造函数并用它完成呢?
如果你写代码,
public class Outer { private class Inner {} }
你会注意到只有一个构造函数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(); } }
编译器必须生成Outer可以合法调用的构造函数(您不能合法地调用私有默认构造函数,因为它是私有的)。 因此编译器必须生成一个新的合成构造函数。 根据JLS第13.1节 ,新构造函数必须是合成的
除了默认构造函数和类初始化方法之外,编译器引入的任何在源代码中没有相应构造的构造都必须标记为合成构造。
第二个构造函数在源代码中没有相应的构造,因此这个新的构造函数必须是合成的。 必须仍然生成第一个私有构造函数,因为JLS需要私有默认构造函数。
这不是一个答案,我认为这个答案很好地涵盖了。 它只是一个产生您描述的行为的工作示例:
public class Outer { private class Inner { } public static void main(String[] args) { printConstructors(); //only one constructor is printed but two would appear if you //uncommented the line below //new Outer().new Inner(); } private static void printConstructors() { Constructor[] constructors = Outer.Inner.class.getDeclaredConstructors(); for (Constructor c : constructors) { System.out.println(c.toGenericString()); } } }
最可能的答案是尊重您在源代码中声明的内容。 这样做仍然允许在声明它时通过reflection使用私有构造函数。
这也避免了检查是否在Inner
类中实际调用了私有构造函数。