为啥编译包含静态嵌套类的类会创建一个名为“EnclosureClass$1”的新 .class 文件? [复制]

Posted

技术标签:

【中文标题】为啥编译包含静态嵌套类的类会创建一个名为“EnclosureClass$1”的新 .class 文件? [复制]【英文标题】:Why does compiling a class containing static nested classes create a new .class file named "EnclosingClass$1"? [duplicate]为什么编译包含静态嵌套类的类会创建一个名为“EnclosureClass$1”的新 .class 文件? [复制] 【发布时间】:2015-03-25 18:49:34 【问题描述】:

在下面的代码中:

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

在与其他 .class 文件一起编译时,我还看到一个名为“EnclosureClass$1.class”的文件。为什么会自动创建它?怎么回事?

【问题讨论】:

这里定义的所有内部类都是静态的 Eclipse 编译器不会生成这样的类文件。 javac 1.8.0_20 确实如此。根据规范 afaik,不需要这样的 .class 文件。它可能会使 javac 的事情变得更容易。 IBiLink 被声明为包本地时,不会生成Enclosing$1,虽然我不明白为什么。 你描述的类签名是一个匿名内部类。 @vsnyc 不错的发现。该线程中的第二个(也是投票最高的)答案更加令人满意,因为 Oak 似乎有一个合理的答案。 ***.com/a/2883541/312407 【参考方案1】:

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

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


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

javap -v EnclosingClass$1.class

产生以下结果

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    

注意类的访问标志包含ACC_SYNTHETIC

ACC_SYNTHETIC 标志表明这个类或接口是 由编译器生成,不会出现在源代码中。

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

javac -XD-printflat EnclosingClass.java

会产生

/*synthetic*/ class EnclosingClass$1 


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

Java 反射教程可以帮助我们理解这一点。看看SyntheticConstructor 类中的 cmets

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

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

再次指定java reflection tutorial

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

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

public static class BiNode extends Sub.IBiLink  

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

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

没有生成EnclosingClass$1.class


调试时发现更多细节

改变

private static class IBiLink

protected static class IBiLink

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

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

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


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

Eclipse 使用它内置的编译器,你可以配置它的严重级别。

默认情况下,对封闭类型的不可访问成员的访问权限设置为 ignore,正如您在这张图片中看到的那样。

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

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

【讨论】:

以上是关于为啥编译包含静态嵌套类的类会创建一个名为“EnclosureClass$1”的新 .class 文件? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

为啥会创建一个名为 Azure Blob 存储容器内文件夹名称的空文件?

java——内部类

在JAVA中啥是顶级类啊

如果在描述块中调用 Factory Girl 为啥会创建重复项

JAVA单元测试

JAVA单元测试