Issue with constructors of nested class

java, nested-class, reflection

Solution

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        
  }

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.

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

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

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        
}

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

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.

Problem

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. Consider the following code: ``` 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); } } } ``` This will prints: ``` a.TestNested$A(a.TestNested) a.TestNested$A(a.TestNested,int) ``` Ok. Next, lets make constructor `A(int a)` private: ``` private A(int a) { } ``` Run program again. Receive: ``` a.TestNested$A(a.TestNested) private a.TestNested$A(a.TestNested,int) ``` 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 } ``` Then input becomes: ``` a.TestNested$A(a.TestNested) private a.TestNested$A(a.TestNested,int) a.TestNested$A(a.TestNested,int,a.TestNested$1) ``` What is it: a.TestNested$A(a.TestNested,int,a.TestNested$1) <<<---?? Ok, lets again make constructor `A(int a)` package local: ``` A(int 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) ``` Questions: 1) How this could be explained? 2) What is this third strange constructor? UPDATE: Investigation shown following. 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) 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); ``` Sorry, but I absolutely don't understand it. UPDATE-2: Further questions are: 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) What Java could use already defined anonymous inner class for those purposes? Isn't this some kind of violation of security?

Original source

Related problems