gpt4 book ai didi

java - 嵌套类的构造函数问题

转载 作者:太空狗 更新时间:2023-10-29 22:55:23 27 4
gpt4 key购买 nike


This question is about interesting behavior of Java: it produces additional (not default) constructor for nested classes in some situations.

This question is also about strange anonymous class, which Java produces with that strange constructor.


考虑以下代码:

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):

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

对不起,我完全不明白。


UPDATE-2:进一步的问题是:

3) 为什么 Java 使用特殊的匿名内部类作为第三个合成构造函数的参数类型?为什么不只是 Object 类型的具有特殊名称的构造函数?

4) 哪些 Java 可以使用已定义的匿名内部类来达到这些目的?这不是某种违反安全的行为吗?

最佳答案

第三个构造函数是由编译器生成的合成构造函数,以允许从外部类访问私有(private)构造函数。这是因为内部类(以及它们的封闭类对其私有(private)成员的访问)只存在于 Java 语言而不是 JVM,因此编译器必须在幕后弥合差距。

反射会告诉你一个成员是否是合成的:

for (Constructor c : aClass.getDeclaredConstructors()) {
System.out.println(c + " " + c.isSynthetic());
}

这打印:

a.TestNested$A(a.TestNested) false
private a.TestNested$A(a.TestNested,int) false
a.TestNested$A(a.TestNested,int,a.TestNested$1) true

有关进一步讨论,请参阅此帖子:Eclipse warning about synthetic accessor for private static nested classes in Java?

编辑: 有趣的是,eclipse 编译器的处理方式与 javac 不同。使用eclipse时,它添加了一个内部类本身类型的参数:

a.TestNested$A(a.TestNested) false
private a.TestNested$A(a.TestNested,int) false
a.TestNested$A(a.TestNested,int,a.TestNested$A) true

我试图通过提前公开该构造函数来阻止它:

class A {    
A() {
}

private A(int a) {
}

A(int a, A another) { }
}

它通过简单地向合成构造函数添加另一个参数来处理这个问题:

a.TestNested$A(a.TestNested) false
private a.TestNested$A(a.TestNested,int) false
a.TestNested$A(a.TestNested,int,a.TestNested$A) false
a.TestNested$A(a.TestNested,int,a.TestNested$A,a.TestNested$A) true

关于java - 嵌套类的构造函数问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14266052/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com