为什么 Java 枚举比接口使用更多内存?
Why do Java Enums uses more memory than Interfaces?
我测试了class、枚举、接口这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时会消耗更少的内存。这是为什么?
使用 javap
实用程序检查 3 个“.class”文件并比较输出。例如:
$ javap -c Company.class
简短的回答是 enum
class 必须实施一些标准方法(values()
、valueOf(String)
、toString()
),但是其他 classes 不必。
话虽如此,“.class”文件的大小不一定能准确预测 class 加载和 JIT 编译时使用的内存。
单个 class 文件定义了 class 或接口。查看结构(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];
}
枚举是 class,如果您查看它编译的结果,就会明白为什么会有必要的开销(参见此处:)。接口是一种抽象类型,实际上只是 class 必须符合的一组操作和常量。
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��
从class文件中可以看出,示例中的接口在方法或标志方面没有添加太多,因此尺寸较小。
我测试了class、枚举、接口这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时会消耗更少的内存。这是为什么?
使用 javap
实用程序检查 3 个“.class”文件并比较输出。例如:
$ javap -c Company.class
简短的回答是 enum
class 必须实施一些标准方法(values()
、valueOf(String)
、toString()
),但是其他 classes 不必。
话虽如此,“.class”文件的大小不一定能准确预测 class 加载和 JIT 编译时使用的内存。
单个 class 文件定义了 class 或接口。查看结构(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];
}
枚举是 class,如果您查看它编译的结果,就会明白为什么会有必要的开销(参见此处:
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��
从class文件中可以看出,示例中的接口在方法或标志方面没有添加太多,因此尺寸较小。