【问题标题】:Why do Java Enums uses more memory than Interfaces?为什么 Java 枚举比接口使用更多内存?
【发布时间】:2016-07-27 14:40:37
【问题描述】:

我测试了class、enum、interface这3种封装常量String的方式。

   public class Company {
        public final static String CAPITAL_ONE = "Capital_One";
    }
    public interface ICompany {
        public final static String CAPITAL_ONE = "Capital_One";
    }
    public enum ECompany {
        CAPITAL_ONE
    }

编译后,它们生成了 330 字节、181 字节和 818 字节的字节码,这意味着接口 ICompany 在加载到 jvm 时将占用更少的内存。这是为什么呢?

【问题讨论】:

  • 也许是因为那些不是等效的数据结构?
  • 接口只需要有一个字段名、类型和值。枚举除了常量值外,还需要存储多个不同的方法实现(values()valueOf(String),以及静态初始化)。

标签: java javacompiler


【解决方案1】:

使用javap 实用程序检查 3 个“.class”文件并比较输出。例如:

$ javap -c Company.class 

简短的回答是enum 类必须实现一些标准方法(values()valueOf(String)toString()),但其他类不必实现。

话虽如此,“.class”文件的大小不一定能准确预测类已加载和 JIT 编译时使用的内存。

【讨论】:

    【解决方案2】:

    单个类文件定义一个类或接口。看结构(https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html):

        ClassFile {
        u4             magic;
        u2             minor_version;
        u2             major_version;
        u2             constant_pool_count;
        cp_info        constant_pool[constant_pool_count-1];
        u2             access_flags;
        u2             this_class;
        u2             super_class;
        u2             interfaces_count;
        u2             interfaces[interfaces_count];
        u2             fields_count;
        field_info     fields[fields_count];
        u2             methods_count;
        method_info    methods[methods_count];
        u2             attributes_count;
        attribute_info attributes[attributes_count];
        }
    

    一个 Enum 是一个类,如果你看看它编译成什么,你就会明白为什么会有必要的开销(见这里:In java, What does such enum type compile to?)。接口是一种抽象类型,它实际上只是类必须遵守的一组操作和常量。

    ICompany.class:

    ����4   
    CAPITAL_ONELjava/lang/String;
    ConstantValue
    SourceFile
    ICompany.javaICompanyjava/lang/ObjectCapital_One
    

    ECompany.class:

    ����4(  
    
    
    !
    
    "
    "   #$CAPITAL_ONE
    LECompany;$VALUES[LECompany;values
    ()[LECompany;CodeLineNumberTablevalueOf(Ljava/lang/String;)LECompany;<init>(Ljava/lang/String;I)V   Signature()V<clinit>Ljava/lang/Enum<LECompany;>;
    SourceFile
    ECompany.java
    %&ECompany'java/lang/Enumclone()Ljava/lang/Object;5(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;@1
    @
        "
    ����    "
    *���*+��7�Y��   �Y� S��
    

    从类文件中可以看出,示例中的接口在方法或标志方面没有添加太多,因此尺寸较小。

    【讨论】:

      猜你喜欢
      • 2013-08-22
      • 2011-02-12
      • 2011-06-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多