从内部类访问Reflection的私有构造函数时,会返回两个构造函数。

4
public class Base {

    private Base instance;

    private Base() {
    }

    public static class BaseHelper {
        Base instance = new Base();
    }
}

在上述示例中,我在基类中有一个无参数构造函数。现在我要像这样列出该类的构造函数:
Constructor<?>[] constructors = Base.class.getDeclaredConstructors();
System.out.println(constructors);

运行这段代码后,我得到了以下输出:
[private com.Base(), com.Base(com.Base)]

这告诉我有两个构造函数:
  • 一个是我声明的私有构造函数
  • 一个是公共默认构造函数
为什么会这样呢?

3
你能解释一下你所说的“但是当我使用反射API时,我可以看到两个构造函数”的意思吗?这两个构造函数是哪两个? - SMA
一旦格式问题解决了,那就是一个好问题。不过我们应该考虑一个更好的标题,这样有类似问题的人可以更容易地找到它... - brimborium
我同意。为什么这个问题有4个踩?这是我最近看到的最好的问题之一。我不相信那些踩的人知道答案。 - Paul Boddington
1个回答

8
编译器创建了两个构造函数,因为你的 BaseHelper 类访问了 Base 类的私有构造函数。
编译时,内部类会从包含类中“提取”出来。如果 BaseHelper 类在 Base 类之外,则不能访问私有构造函数 - 这就是编译器创建第二个构造函数的原因。这就是您看到的第二个构造函数。 Synthetic 是字段修饰符,实质上是由编译器生成的。
package de.test;

import java.lang.reflect.Constructor;

public class Base {

    private Base instance;

    private Base() {
    }

    public static class BaseHelper {
        Base instance = new Base();
    }

    public static void main(String[] args) {
        Constructor[] constructors = Base.class.getDeclaredConstructors();
        for (Constructor constructor : constructors) {
            System.out.println(constructor + " - synthetic? " + constructor.isSynthetic());
        }
    }
}

2
谢谢Max的回答,我还有一个疑问,为什么它会创建带参数的构造函数(正如我在问题中提到的)。 - Amit
我在这方面找不到可靠的来源,但我猜测构造函数需要一个类型为“Base”的对象,以避免其他代码通过反射调用此构造函数。 - maxdev
不是Base,而是Base$1。看起来还创建了一个合成类。 - Paul Boddington
我也得到了与maxDev相同的输出。private Base() - synthetic? false和Base(Base) - synthetic? true(java 1.6.0_27)。 - Amit
3
他们显然已决定将其更改为Java 8。我认为maxdev关于需要一个Base的解释(防止您通过反射调用此构造函数)非常有道理。但是漏洞在于,Base可能有另一个公共构造函数,例如接受一个String。在这种情况下,如果BaseHelper调用私有无参构造函数,则仍需要合成构造函数,并且您可以通过传递使用String构造的Base来调用合成构造函数。创建一个合成类可以使整个过程更加严谨。 - Paul Boddington
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接