Java:私有内部类合成构造函数
我有一个Java:私有内部类合成构造函数,java,inner-classes,Java,Inner Classes,我有一个外部类,它有一个私有内部类 在我的外部类方法中,我将内部类实例化如下: Outer outer = new Outer(); Inner inner = outer.new Inner(); 编译器将此代码转换为: Outer outer = new Outer(); Inner inner = new Inner(outer, null); 使用反射显示内部类具有以下合成构造函数: private Outer$Inner(Outer) Outer$Inner(Outer,Outer
外部
类,它有一个私有内部
类
在我的外部
类方法中,我将内部
类实例化如下:
Outer outer = new Outer();
Inner inner = outer.new Inner();
编译器将此代码转换为:
Outer outer = new Outer();
Inner inner = new Inner(outer, null);
使用反射显示内部
类具有以下合成构造函数:
private Outer$Inner(Outer)
Outer$Inner(Outer,Outer$Inner)
由于internal
类是private
,编译器向其添加private
构造函数,因此没有人可以实例化该类。但是显然,Outer
类应该能够实例化它,因此编译器添加了另一个包私有构造函数,该构造函数反过来调用私有构造函数。另外,由于包私有构造函数的名称中有$
,所以普通Java代码不能调用它
问题:为什么要合成一个私有构造函数和一个包私有构造函数?为什么不只合成包私有构造函数并使用它呢?最可能的答案是尊重您在源代码中声明的内容。这样做仍然允许在声明私有构造函数时通过反射使用它
这也避免了检查私有构造函数是否在
内部
类中实际调用
public class Outer {
private class Inner {}
}
public class Outer {
private class Inner {}
public String foo() {
return new Inner().toString();
}
}
您将注意到,只有一个构造函数private Outer$Inner(Outer)
该构造函数是第节要求的,该节规定,如果未定义构造函数,则必须生成默认构造函数,在这种情况下,默认构造函数必须是私有的
在类类型中,如果该类声明为public,则默认
构造函数隐式地被赋予访问修饰符public(§6.6);如果
该类声明为受保护,则默认构造函数为
隐式给出受保护的访问修饰符(§6.6);如果班级是
声明为private,则默认构造函数被隐式地指定为
访问修改器专用(§6.6);否则,默认构造函数将
无访问修饰符暗示的默认访问权限
但是,当您使用如下代码实例化一个内部-外部的实例时
public class Outer {
private class Inner {}
}
public class Outer {
private class Inner {}
public String foo() {
return new Inner().toString();
}
}
编译器必须生成外部可以合法调用的构造函数(不能合法调用私有默认构造函数,因为它是私有的)。因此,编译器必须生成一个新的合成构造函数。新的构造函数必须是合成的,根据
编译器引入的任何没有
源代码中相应的构造必须标记为
合成,默认构造函数和类除外
初始化方法
第二个构造函数在源代码中没有相应的构造函数,因此这个新构造函数必须是合成的。第一个私有构造函数仍然必须生成,因为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());
}
}
}
@Noofiz这些构造函数是由编译器创建的,没有显式地为它们编码;因此我称之为“合成”。@Noofiz如果你不理解这个问题,我建议你把它留给那些理解它的人。
Outer$Inner(Outer,Outer$Inner)
真的正确吗?构造函数获取与参数相同的类的实例?编译器为什么要添加这样一个参数。@Philipp Wendler这是正确的。编译器重载它,以便它不会与私有构造函数签名冲突。还要注意,在实例化过程中,编译器将该参数作为“null”传递给构造函数(如我的代码所示)。感谢您指出我的错误。-可能是重复的?为什么实例化内部的新实例是非法的?我还是能做到的,对吗?而且,既然这个私有构造函数是由编译器生成的,为什么它不是一个合成构造函数呢?现在很清楚了。Thx!-这里已经有答案了