Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/306.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java:私有内部类合成构造函数_Java_Inner Classes - Fatal编程技术网

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!-这里已经有答案了