枚举类反编译
枚举类关键字enum
隐藏了很多细节,导致我们不方便理解,查阅资料后,发现反编译class文件,是一种窥探JVM运行Java代码的一种有效手段。本文大量借鉴了知乎文章 1
1 | public enum Gender { |
使用jad反编译工具对枚举类Gender进行分析:
1 | // Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov. |
由此可以分析出以下结论:
1 | public final class Gender extends Enum {} |
我们声明的枚举类是final类型的,所以无法被继承
我们声明枚举类默认都会继承自抽象类Enum,稍后会分析下Enum的源码
1 | public static final Gender MALE; |
声明的枚举类常量其实是一个public static final枚举类对象,所以无法被更改
$VALUES[]数组用来保存所有枚举类对象
(这里稍稍补充一下:$是由Java编译器生成的占位符,一般不推荐代码中使用)
1 | static { |
- 静态代码块用来初始化枚举类对象(常量),并初始化VALUES[]数组
1 | private Gender(String s, int i){ |
枚举类的构造方法是私有的,它只能内部调用,所以无法在外部被初始化,即无法被new
他调用了超类的构造器,
String s
是枚举类对象的值,int i
是枚举类对象的ordinal的值
1 | public static Gender[] values(){ |
- 静态的values()方法,用于返回所有的类对象,这个clone()方法是Object对象的浅拷贝方法,只会复制并返回对象的引用 2
1 | public static Gender valueOf(String name){ |
- 静态的valueOf()方法,根据name参数返回对应的类对象
Enum源码分析
Enum类在java源码中的相对路径为:/rt.jar!/java/lang/Enum.class
1 | import java.io.Serializable; |
由此可以分析出以下结论:
1 | private final String name; |
- Enum类有两个成员变量:name和ordinal。其中,name用于记录枚举常量的名字。ordinal用于记录枚举常量在声明时的顺序(从0开始)。
1 | protected Enum(String name, int ordinal) { |
- 受保护的构造方法,反编译出来的构造器中,super调用的就是上边这个方法;
1 | public String toString() { |
Enum类重写了toString()方法,返回枚举常量的name值。
Enum类重写了equals()方法,直接用等号比较。
Enum类直接调用Object的hashCode()方法。
1 | protected final Object clone() throws CloneNotSupportedException { |
- Enum类不允许克隆,clone()方法直接抛出异常。(保证枚举永远是单例的)
1 | public final int compareTo(E o) { |
- Enum类实现了Comparable接口,直接比较枚举常量的ordinal的值。
1 | public static <T extends Enum<T>> T valueOf(Class<T> enumType, String name) { |
- Enum类有一个静态的valueOf()方法,可以根据枚举类型以及name返回对应的枚举常量。
1 | private void readObject(ObjectInputStream in) throws IOException,ClassNotFoundException { |
- Enum类不允许反序列化,为了保证枚举永远是单例的。
1 |
|
- 返回表示此枚举常量的枚举类型的Class对象,反射时使用。
Reference
1. 枚举的本质 ↩
2. Java Object clone() 方法 ↩