这个问题涉及Java的有趣行为:在某些情况下,它会为嵌套类生成额外(非默认)的构造函数。
这个问题也涉及奇怪的匿名类,Java会使用那个奇怪的构造函数生成它。
考虑以下代码:
package a;
import java.lang.reflect.Constructor;
public class TestNested {
class A {
A() {
}
A(int a) {
}
}
public static void main(String[] args) {
Class<A> aClass = A.class;
for (Constructor c : aClass.getDeclaredConstructors()) {
System.out.println(c);
}
}
}
这将会输出:
a.TestNested$A(a.TestNested)
a.TestNested$A(a.TestNested,int)
好的,接下来让我们将构造函数A(int a)
设置为私有:
private A(int a) {
}
再次运行程序。收到以下信息:a.TestNested$A(a.TestNested)
private a.TestNested$A(a.TestNested,int)
现在这样也可以。但是让我们修改main()
方法,按以下方式添加新的A
类实例:
public static void main(String[] args) {
Class<A> aClass = A.class;
for (Constructor c : aClass.getDeclaredConstructors()) {
System.out.println(c);
}
A a = new TestNested().new A(123); // new line of code
}
然后输入变成:
a.TestNested$A(a.TestNested)
private a.TestNested$A(a.TestNested,int)
a.TestNested$A(a.TestNested,int,a.TestNested$1)
什么是它:a.TestNested$A(a.TestNested,int,a.TestNested$1) <<<---??
好的,让我们再次将构造函数A(int a)
设为包级私有:
A(int a) {
}
再次运行程序(不要删除包含A
创建实例的行!),输出结果与第一次相同:a.TestNested$A(a.TestNested)
a.TestNested$A(a.TestNested,int)
问题:
1) 这个可以如何解释?
2) 这第三个奇怪的构造函数是什么?
更新: 调查结果如下。
1) 让我们尝试从其他类中使用反射调用这个奇怪的构造函数。
我们将无法做到这一点,因为没有任何方法可以创建那个奇怪的TestNested$1
类的实例。
2) 好吧。让我们来一个诡计。让我们在TestNested
类中添加这样一个静态字段:
public static Object object = new Object() {
public void print() {
System.out.println("sss");
}
};
好的,现在我们可以从另一个类中调用这个第三个奇怪的构造函数:
TestNested tn = new TestNested();
TestNested.A a = (TestNested.A)TestNested.A.class.getDeclaredConstructors()[2].newInstance(tn, 123, TestNested.object);
抱歉,但我完全不理解。
更新-2:更多的问题是:
3) 为什么Java在这个第三个合成构造函数的参数类型中使用特殊的匿名内部类?为什么不只是Object
类型,或者使用带有特殊名称的构造函数?
4) Java为什么要用已定义的匿名内部类来实现这些目的?这不是某种安全违规吗?
a.TestNested$1
是什么?通过反射调查,这个类甚至没有任何构造函数,并且不能使用反射实例化。 - AndremoniyObject
作为参数类型,因为您可以拥有一个带有Object
参数的构造函数并在没有反射的情况下调用它(通过编译具有非私有A(int,Object)
构造函数的A
,将TestNested$A.class
文件保存在其他地方,删除新构造函数,重新编译TestNested
,并用具有A(int,Object)
构造函数的版本替换新的TestNested$A.class
)。使用匿名类型(TestNested$1
)作为合成构造函数的参数类型可以防止这种情况的发生。 - matts