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

时间:2013-03-04 10:22:52

标签: java inner-classes

我有一个Outer类,其中private Inner类。

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

Outer outer = new Outer();
Inner inner = outer.new Inner();

编译器将此代码转换为:

Outer outer = new Outer();
Inner inner = new Inner(outer, null);

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

private Outer$Inner(Outer)
Outer$Inner(Outer,Outer$Inner)

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

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

3 个答案:

答案 0 :(得分:13)

如果您编写代码,

public class Outer {
      private class Inner {}
}

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

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

  

在类类型中,如果该类声明为public,则为默认值   构造函数隐式赋予访问修饰符public(§6.6);如果   该类被声明为protected,然后是默认构造函数   隐式赋予访问修饰符保护(第6.6节);如果是这样的话   声明为private,然后隐式给出默认构造函数   access modifier private(§6.6);否则,默认构造函数具有   无访问修饰符隐含的默认访问权限。

但是,当您使用类似的代码

实例化Inner inside Outer的实例时
public class Outer {
    private class Inner {}
        public String foo() {
            return new Inner().toString(); 
        }
}

编译器必须生成Outer可以合法调用的构造函数(您不能合法地调用私有默认构造函数,因为它是私有的)。因此编译器必须生成一个新的合成构造函数。根据{{​​3}}

,新构造函数必须是合成的
  

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

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

答案 1 :(得分:3)

这不是一个答案,我认为sbridges已经很好地解决了这个问题。它只是一个产生您描述的行为的工作示例:

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());
        }
    }
}

答案 2 :(得分:2)

最可能的答案是尊重您在源代码中声明的内容。这样做仍然允许在声明它时通过反射使用私有构造函数。

这也避免了检查私有构造函数是否实际在Inner类中调用。