为什么编译包含静态嵌套类的类会创建一个名为"EnclosingClass $ 1"的新.class文件?

pai*_*dly 17 java javac nested-class .class-file

在以下代码中:

 class EnclosingClass
 { 
     public static class BiNode extends Sub.IBiLink { }
     private static class Sub
     {
         private static class IBiLink
         {  
         } 
     }
}
Run Code Online (Sandbox Code Playgroud)

在与其他.class文件一起编译时,我还看到一个名为"EnclosingClass $ 1.class"的文件.为什么这是自动创建的?这是怎么回事?

Jea*_*ard 5

首先查看 JVM 规范中的类访问和属性修饰符表。

在此处输入图片说明

请注意ACC_SYNTHETIC解释指定它不存在于源代码中的标志(简单来说,它将在编译器生成类时添加)。


让我们看看字节码EnclosingClass$1.class(注意,我只会粘贴重要的部分)。

javap -v EnclosingClass$1.class
Run Code Online (Sandbox Code Playgroud)

产生以下结果

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    
Run Code Online (Sandbox Code Playgroud)

请注意,该类的访问标志包含ACC_SYNTHETIC.

ACC_SYNTHETIC 标志表示这个类或接口是由编译器生成的,并且没有出现在源代码中。

确保生成的类是合成的另一个选项是编译为

javac -XD-printflat EnclosingClass.java
Run Code Online (Sandbox Code Playgroud)

这会产生

/*synthetic*/ class EnclosingClass$1 {
}
Run Code Online (Sandbox Code Playgroud)

很好,但为什么要生成一个合成类?

Java 反射教程可以帮助我们理解这一点。看看SyntheticConstructor课堂上的评论

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

因此,根据评论,EnclosingClass$1.class创建合成类是因为它IBiLink是私有的。

再次,java反射教程此时指定

由于内部类的构造函数引用了封闭类的私有构造函数,编译器必须生成一个包私有构造函数。

在我们的例子中,我们没有明确地看到任何构造函数调用,但我们有这一行

public static class BiNode extends Sub.IBiLink { }
Run Code Online (Sandbox Code Playgroud)

让我们尝试编译这段代码,看看会发生什么

class EnclosingClass
 { 
     //public static class BiNode extends Sub.IBiLink { }
     private static class Sub
     {
         private static class IBiLink
         {  
         } 
     }
}
Run Code Online (Sandbox Code Playgroud)

没有EnclosingClass$1.class生成。


调试时注意到的更多细节

改变

private static class IBiLink
Run Code Online (Sandbox Code Playgroud)

protected static class IBiLink
Run Code Online (Sandbox Code Playgroud)

请注意,在编译时,EnclosingClass$1.class不会创建。

为什么保护类没有生成合成类?

仅仅因为在保护类时,您可以隐式地访问每个超类。


为什么eclipse编译器不生成合成类?

Eclipse 使用它内置的编译器,您可以在其中配置它的严重性级别。

默认情况下,对封闭类型的不可访问成员的访问设置为忽略,如您在此图像中所见。

在此处输入图片说明

例如将其更改为警告,您将收到以下消息。

在此处输入图片说明

这让我相信 eclipse,altought 不会创建其他类,会模拟它来模拟合成成员。