在日常开发中,经常会用到枚举类。这篇文章主要探讨一下枚举类和普通类有什么区别,以及编译过程中偷偷做了什么事情。
知识点
- 枚举类的本质
- 编译器对枚举类的改动
先看一段简单的枚举类代码:
enum StatusType {ON(1) ,OFF(2);StatusType(int code) {this.code = code;}private final int code;}
使用Compiler Explorer工具,编译成字节码
从上面的截图中可以看到,枚举类本质上也是一个普通类,同时继承了Enum类,而且还是final的。所以说类可以做到的事情,枚举类也可以,比如定义成员变量和成员方法。
除了自动继承了Enum类,还声明了一些静态变量和静态方法。
我们在枚举类定义的ON
和OFF
对象,本质是一个静态变量。
public static final StatusType ON;public static final StatusType OFF;
在开发中经常用到的values()和valueOf()方法,也是编译器自动帮忙生成的
private static final StatusType[] $VALUES;public static StatusType[] values();0: getstatic #10 // Field $VALUES:[LStatusType;3: invokevirtual #14 // Method "[LStatusType;".clone:()Ljava/lang/Object;6: checkcast #15 // class "[LStatusType;"9: areturnpublic static StatusType valueOf(java.lang.String);0: ldc #4 // class StatusType2: aload_03: invokestatic #5 // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;6: checkcast #4 // class StatusType9: areturn
上面只是声明定义了一个静态变量,还未进行初始化,下面static块进行初始化
static {};0: new #1 // class StatusType3: dup4: ldc #33 // String ON6: iconst_07: iconst_18: invokespecial #34 // Method "<init>":(Ljava/lang/String;II)V11: putstatic #3 // Field ON:LStatusType;14: new #1 // class StatusType17: dup18: ldc #37 // String OFF20: iconst_121: iconst_222: invokespecial #34 // Method "<init>":(Ljava/lang/String;II)V25: putstatic #7 // Field OFF:LStatusType;28: invokestatic #38 // Method $values:()[LStatusType;31: putstatic #10 // Field $VALUES:[LStatusType;34: return
上面这段字节码主要就是创建了两个实例对象和一个数组,并且把两个实例对象放到数组里。不过有个点可以注意到,在调用构造函数的时候, 调用的是3个参数的构造函数,这里实际上前面两个参数是父类的构造函数需要的。
8: invokespecial #34 // Method "<init>":(Ljava/lang/String;II)V
/*** Sole constructor. Programmers cannot invoke this constructor.* It is for use by code emitted by the compiler in response to* enum type declarations.** @param name - The name of this enum constant, which is the identifier* used to declare it.* @param ordinal - The ordinal of this enumeration constant (its position* in the enum declaration, where the initial constant is assigned* an ordinal of zero).*/protected Enum(String name, int ordinal) {this.name = name;this.ordinal = ordinal;}
总结
1、枚举类本质上也是普通类,并且是final修饰的,继承了Enum类
2、用户定义的枚举对象转换成了静态变量对象
3、枚举类自动添加了values()和valueOf()方法
4、调用构造函数时,会自动调用父类的构造函数