Why does compiling a class containing static nested classes create a new .class file named "EnclosingClass$1"? [duplicate]
Asked Answered
G

1

19

In the below code :

 class EnclosingClass
 { 
     public static class BiNode extends Sub.IBiLink { }
     private static class Sub
     {
         private static class IBiLink
         {  
         } 
     }
}

On compiling along with other .class files, I also see a file named "EnclosingClass$1.class" .Why has this been automatically created? Whats going on?

Gastro answered 25/3, 2015 at 18:49 Comment(9)
All the inner classes defined here are staticGastro
The Eclipse compiler doesn't generate such a class file. javac 1.8.0_20 does. There is no requirement for such a .class file according to the spec afaik. It may make things easier for javac.Toowoomba
When IBiLink is declared as package-local, no Enclosing$1 is generated, although I don't understand why.Discourse
The class signature you describe is for an anonymous inner class.Inoculum
Interesting question. I couldn't figure it out either, but after some testing, I did notice that EnclosingClass$1.class is only generated when IBiLink is private.Aishaaisle
@vsnyc Nice find. The second (and highest voted) answer in that thread is even more satisfying, as Oak seems to have a plausible answer. https://mcmap.net/q/16028/-why-is-an-anonymous-inner-class-containing-nothing-generated-from-this-codeStereoisomerism
This can't be closed as duplicate while the bounty is open though.Samora
@SotiriosDelimanolis What is the version of the build path on your eclipse ?Dannielledannon
@Jean-FrançoisSavard Do you mean the Compiler Compliance Level? 1.8Toowoomba
E
5

First have a look at the class access and propery modifier table from the JVM specifications.

enter image description here

Notice the ACC_SYNTHETIC flag which interpretation specify that it is not present in the source code (in simplier words, it will be added when the class is generated by the compiler).


Let's have a look at the bytecode of EnclosingClass$1.class (note that I will paste only the part that matter).

javap -v EnclosingClass$1.class

produce the following result

Classfile /C:/Users/jfrancoiss/Desktop/Nouveau dossier/EnclosingClass$1.class
  Last modified 2015-03-31; size 190 bytes
  MD5 checksum 5875440f1e7f5ea9a519d02fbec6dc8f
  Compiled from "EnclosingClass.java"
class EnclosingClass$1
  minor version: 0
  major version: 52
  flags: ACC_SUPER, ACC_SYNTHETIC    

Notice that the access flags of the class contains ACC_SYNTHETIC.

The ACC_SYNTHETIC flag indicates that this class or interface was generated by a compiler and does not appear in source code.

An other option to make sure the generated class is synthetic is to compile as

javac -XD-printflat EnclosingClass.java

which would produce

/*synthetic*/ class EnclosingClass$1 {
}

Great, but why generate a synthetic class ?

The Java reflection tutorial can help us understand this. Have a look at the comments in the SyntheticConstructor class

public class SyntheticConstructor {
    private SyntheticConstructor() {}
    class Inner {
    // Compiler will generate a synthetic constructor since
    // SyntheticConstructor() is private.
    Inner() { new SyntheticConstructor(); }
    }
}

So according on the comment, the synthetic class EnclosingClass$1.class was created because IBiLink was private.

Once again, the java reflection tutorial specify at this point

Since the inner class's constructor references the private constructor of the enclosing class, the compiler must generate a package-private constructor.

In our case, we do not see explicitely any constructor call, but we have this line

public static class BiNode extends Sub.IBiLink { }

Let's try compiling this code and see what happen

class EnclosingClass
 { 
     //public static class BiNode extends Sub.IBiLink { }
     private static class Sub
     {
         private static class IBiLink
         {  
         } 
     }
}

No EnclosingClass$1.class generated.


More details noticed when debugging

Change

private static class IBiLink

to

protected static class IBiLink

notice that when compiling, EnclosingClass$1.class is not created.

why does protecting the class did not generate a synthetic class ?

Simply because when protecting the class, you implicitely get access to each of the super classes.


Why don't eclipse compiler generate a synthetic class ?

Eclipse use it built-in compiler, which you can configure it severity level.

By default, Access to a non-accessible member of an enclosing type is set to ignore as you can see on this image.

enter image description here

Change it for example to warning and you will get the following message.

enter image description here

which let me believe that eclipse, altought does not create an other class, will emulate it to simulate the synthetic member.

Elgon answered 31/3, 2015 at 13:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.