Java 枚举和其他类文件

标签 java enums

我注意到 enums 在编译后引入了许多额外的类文件 (Class$1),使总大小膨胀。它似乎附加到每个甚至使用枚举的类,而且这些类通常是重复的。

为什么会发生这种情况,有没有办法在不删除枚举的情况下防止这种情况发生。

(问题的原因是空间对我来说非常宝贵)

编辑

在进一步调查此问题时,Sun 的 Javac 1.6 会在您每次在枚举上使用开关时创建一个额外的合成类。它使用某种 SwitchMap。 This网站有更多信息,here告诉你如何分析 Javac 在做什么。

每次在枚举上使用开关时,额外的物理文件似乎要付出高昂的代价!

有趣的是,Eclipe 的编译器不会生成这些附加文件。我想知道是否唯一的解决方案是切换编译器?

最佳答案

我只是被这种行为所困扰,在谷歌搜索时出现了这个问题。我想我会分享我发现的一点点额外信息。

每次您在枚举上使用开关时,javac 1.5 和 1.6 都会创建一个额外的合成类。该类包含一个所谓的“开关映射”,它将枚举索引映射到开关表跳转数。重要的是,合成类是为发生切换的类创建的,不是枚举类。

这是生成内容的示例:

枚举类.java

public enum EnumClass { VALUE1, VALUE2, VALUE3 }

枚举用户.java

public class EnumUser {
    public String getName(EnumClass value) {
        switch (value) {
            case VALUE1: return "value 1";
            // No VALUE2 case.
            case VALUE3: return "value 3";
            default:     return "other";
        }
    }
}

合成 EnumUser$1.class

class EnumUser$1 {
    static final int[] $SwitchMap$EnumClass = new int[EnumClass.values().length];

    static {
        $SwitchMap$EnumClass[EnumClass.VALUE1.ordinal()] = 1;
        $SwitchMap$EnumClass[EnumClass.VALUE3.ordinal()] = 2;
    };
}

然后使用此开关映射为 lookupswitchtableswitch JVM 指令生成索引。它将每个枚举值转换为从 1 到 [switch case 的数量] 的相应索引。

枚举用户类

public java.lang.String getName(EnumClass);
  Code:
   0:   getstatic       #2; //Field EnumUser$1.$SwitchMap$EnumClass:[I
   3:   aload_1
   4:   invokevirtual   #3; //Method EnumClass.ordinal:()I
   7:   iaload
   8:   lookupswitch{ //2
                1: 36;
                2: 39;
                default: 42 }
   36:  ldc     #4; //String value 1
   38:  areturn
   39:  ldc     #5; //String value 3
   41:  areturn
   42:  ldc     #6; //String other
   44:  areturn

tableswitch 在存在三个或更多 switch 情况时使用,因为与 lookupswitch 的线性搜索相比,它执行更高效的恒定时间查找。从技术上讲,当 javac 使用 lookupswitch 时,它可以通过合成开关映射省略整个业务。

推测:我手头没有 Eclipse 的编译器可以用来测试,但我想它不会为合成类烦恼,只需使用 lookupswitch。或者它可能需要比原始提问者在“升级”到 tableswitch 之前测试的更多开关案例。

关于Java 枚举和其他类文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36844524/

相关文章:

java - JPA 延迟加载性能优势有多重要?

java - 布局管理器和滚动 Pane 的一些问题,不显示对象

java - 检索多个子分支 Firebase

Java:枚举还是用数字编码?

Java Enum 表现得很奇怪

java - 从 JDialog 返回时出现意外结果

C++:使用结构或枚举来重载构造函数之间的区别?

c++ - 我可以在 C++ 中使用未标记值的枚举吗?

swift - 通用枚举函数参数?

javascript - 如何使用枚举值作为数组的索引