在日常开发中,经常会用到枚举类。这篇文章主要探讨一下枚举类和普通类有什么区别,以及编译过程中偷偷做了什么事情。
知识点
- 枚举类的本质
- 编译器对枚举类的改动
先看一段简单的枚举类代码:
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: areturn
public static StatusType valueOf(java.lang.String);
0: ldc #4 // class StatusType
2: aload_0
3: invokestatic #5 // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
6: checkcast #4 // class StatusType
9: areturn
上面只是声明定义了一个静态变量,还未进行初始化,下面static块进行初始化
static {};
0: new #1 // class StatusType
3: dup
4: ldc #33 // String ON
6: iconst_0
7: iconst_1
8: invokespecial #34 // Method "<init>":(Ljava/lang/String;II)V
11: putstatic #3 // Field ON:LStatusType;
14: new #1 // class StatusType
17: dup
18: ldc #37 // String OFF
20: iconst_1
21: iconst_2
22: invokespecial #34 // Method "<init>":(Ljava/lang/String;II)V
25: 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、调用构造函数时,会自动调用父类的构造函数