本文介绍了嵌套类的构造函数的问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个问题也是关于奇怪的匿名类,Java
使用那个奇怪的构造函数生成。

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)

好的。接下来,让make构造函数 A(int a) private:

Ok. Next, lets make constructor A(int a) private:

    private A(int a) {
    }

再次运行程序。接收:

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

也没关系。但是现在,让我们以这种方式修改 main()方法(添加类 A 创建的新实例): / p>

It is also ok. But now, lets modify main() method in such way (addition of new instance of class A creation):

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

What is it: a.TestNested$A(a.TestNested,int,a.TestNested$1) <<<---??

Ok ,让我们再次构造构造函数 A(int a)包本地:

Ok, lets again make constructor A(int a) package local:

    A(int a) {
    }

再次重新运行程序(我们 don' t删除行与 A 创建!),输出与第一次一样:

Rerun program again (we don't remove line with instance of A creation!), output is as in the first time:

a.TestNested$A(a.TestNested)
a.TestNested$A(a.TestNested,int)






问题:

1)如何解释这个问题?

2)这第三个奇怪的构造函数是什么?

2) What is this third strange constructor?

更新:以下调查显示。

1)让我们尝试使用来自其他类的反射来调用这个奇怪的构造函数。
我们无法做到这一点,因为没有办法创建那个奇怪的 TestNested $ 1 类的实例。

1) Lets try to call this strange constructor using reflection from other class.We will not able to do this, because there isn't any way to create instance of that strange TestNested$1 class.

2)好的。让我们来做。让我们添加到类 TestNested 这样的静态字段:

2) Ok. Lets do the trick. Lets add to the class TestNested such static field:

public static Object object = new Object() {
    public void print() {
        System.out.println("sss");
    }
};

嗯?好的,现在我们可以从另一个类调用第三个奇怪的构造函数:

Well? Ok, now we could call this third strange constructor from another class:

    TestNested tn = new TestNested();
    TestNested.A a = (TestNested.A)TestNested.A.class.getDeclaredConstructors()[2].newInstance(tn, 123, TestNested.object);

抱歉,我绝对不明白。

UPDATE-2:更多问题是:

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

3) Why Java use special anonymous inner class for an argument type for this third synthetic constructor? Why not just Object type, of constructor with special name?

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

4) What Java could use already defined anonymous inner class for those purposes? Isn't this some kind of violation of security?

推荐答案

首先,感谢您提出这个有趣的问题。我很好奇,以至于无法抗拒看看字节码。这是 TestNested的字节码

First of all, thank you for this interesting question. I was so intrigued that I could not resist taking a look at the bytecode. This is the bytecode of TestNested:

Compiled from "TestNested.java"
  public class a.TestNested {
    public a.TestNested();
      Code:
         0: aload_0       
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return        

    public static void main(java.lang.String[]);
      Code:
         0: ldc_w         #2                  // class a/TestNested$A
         3: astore_1      
         4: aload_1       
         5: invokevirtual #3                  // Method java/lang/Class.getDeclaredConstructors:()[Ljava/lang/reflect/Constructor;
         8: astore_2      
         9: aload_2       
        10: arraylength   
        11: istore_3      
        12: iconst_0      
        13: istore        4
        15: iload         4
        17: iload_3       
        18: if_icmpge     41
        21: aload_2       
        22: iload         4
        24: aaload        
        25: astore        5
        27: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
        30: aload         5
        32: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
        35: iinc          4, 1
        38: goto          15
        41: new           #2                  // class a/TestNested$A
        44: dup           
        45: new           #6                  // class a/TestNested
        48: dup           
        49: invokespecial #7                  // Method "<init>":()V
        52: dup           
        53: invokevirtual #8                  // Method java/lang/Object.getClass:()Ljava/lang/Class;
        56: pop           
        57: bipush        123
        59: aconst_null   
        60: invokespecial #9                  // Method a/TestNested$A."<init>":(La/TestNested;ILa/TestNested$1;)V
        63: astore_2      
        64: return        
  }

如您所见,构造函数 a.TestNested $ A(a.TestNested,int,a.TestNested $ 1)从您的<$调用c $ c> main 方法。此外, null 作为 a.TestNested $ 1 参数的值传递。

As you can see, the constructor a.TestNested$A(a.TestNested,int,a.TestNested$1) is invoked from your main method. Furthermore, null is passed as the value of the a.TestNested$1 parameter.

让我们来看看神秘的匿名类 a.TestNested $ 1

So let's take a look at the mysterious anonymous class a.TestNested$1:

Compiled from "TestNested.java"
class a.TestNested$1 {
}

奇怪 - 我本来希望这个班级能够真正做点什么。要理解它,让我们看一下中的构造函数a.TestNested $ A
class a.TestNested $ A {
final a.TestNested这个$ 0;

Strange - I would have expected this class to actually do something. To understand it, let's take a look at the constructors in a.TestNested$A: class a.TestNested$A { final a.TestNested this$0;

  a.TestNested$A(a.TestNested);
    Code:
       0: aload_0       
       1: aload_1       
       2: putfield      #2                  // Field this$0:La/TestNested;
       5: aload_0       
       6: invokespecial #3                  // Method java/lang/Object."<init>":()V
       9: return        

  private a.TestNested$A(a.TestNested, int);
    Code:
       0: aload_0       
       1: aload_1       
       2: putfield      #2                  // Field this$0:La/TestNested;
       5: aload_0       
       6: invokespecial #3                  // Method java/lang/Object."<init>":()V
       9: return        

  a.TestNested$A(a.TestNested, int, a.TestNested$1);
    Code:
       0: aload_0       
       1: aload_1       
       2: iload_2       
       3: invokespecial #1                  // Method "<init>":(La/TestNested;I)V
       6: return        
}

查看包裹 - 可见构造函数 a.TestNested $ A(a.TestNested,int,a.TestNested $ 1),我们可以看到第三个参数被忽略。

Looking at the package-visible constructor a.TestNested$A(a.TestNested, int, a.TestNested$1), we can see that the third argument is ignored.

现在我们可以解释构造函数和匿名内部类。为了避免私有构造函数的可见性限制,需要额外的构造函数。这个额外的构造函数只是委托给私有构造函数。但是,它不能与私有构造函数具有完全相同的签名。因此,添加匿名内部类以提供唯一的签名,而不会与其他可能的重载构造函数发生冲突,例如具有签名(int,int)或<$的构造函数C $ C>(INT,对象)。由于这个匿名内部类只需要创建一个唯一的签名,因此不需要实例化它,也不需要有内容。

Now we can explain the constructor and the anonymous inner class. The additional constructor is required in order to circumvent the visibility restriction on the private constructor. This additional constructor simply delegates to the private constructor. However, it cannot have the exact same signature as the private constructor. Because of this, the anonymous inner class is added to provide a unique signature without colliding with other possible overloaded constructors, such as a constructor with signature (int,int) or (int,Object). Since this anonymous inner class is only needed to create a unique signature, it does not need to be instantiated and does not need to have content.

这篇关于嵌套类的构造函数的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-24 13:42