有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

嵌套类构造函数的java问题


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 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)这是怎么解释的

第三个奇怪的构造器是什么


更新:调查如下所示

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可以使用已经定义的匿名内部类来实现这些目的?这不是某种违反安全的行为吗


共 (1) 个答案

  1. # 1 楼答案

    第三个构造函数是编译器生成的合成构造函数,以便允许从外部类访问私有构造函数。这是因为内部类(以及它们的封闭类对其私有成员的访问)只存在于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?

    EDIT:有趣的是,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