写在前面
一直对Enum的实现原理有困惑,所以最近专门去查了查,了解到了Java的12个语法糖,决定依次学习记录一下。
Enum示例
我们先写个简单的Enum的java程序并编译一下。
1 | public enum Week { |
编译程序得到class文件并用jad(下载地址)反编译该文件jad \Week.class
,javap只能反编译为字节码,查看较为麻烦。
得到源码:
1 | // Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov. |
构造函数
我们可以看到Enum其实本质还是类,所有的Enum都继承自Enum基类。
分析构造函数,我们定义的枚举常量
的名字都用String
类存储,并且函数会自动给常量分配一个ordinal
,用来记录记录枚举常量在声明时的顺序,剩下的参数是我们在枚举中定义的参数。
super函数内容:
1 | protected Enum(String name, int ordinal) { |
static代码块
static代码块是对枚举类进行初始化并存入到$VALUES数组中。
values函数
返回所有的枚举常量,这个很好理解。
valueOf函数
valueOf函数通过枚举常量的名字来返回枚举常数。
函数内使用的是基类Enum中的valueOf函数,并传入Week参数,来和其他Enum类区分
1 | public static <T extends Enum<T>> T valueOf(Class<T> enumType, |
enumType.enumConstantDirectory()
函数会返回所有一个包含所有枚举常量的HashMap
。
1 | Map<String, T> enumConstantDirectory() { |
一些细节
该部分摘自枚举的本质
Jvm编译器处理枚举的做了以下几件事:
- 定义一个继承自Enum类的Fruit类,Fruit类是用final修饰的
- 为每个枚举实例对应创建一个类对象,这些类对象是用public static final修饰的。同时生成一个数组,用于保存全部的类对象
- 生成一个静态代码块,用于初始化类对象和类对象数组
- 生成一个构造函数,构造函数包含自定义参数和两个默认参数
- 生成一个静态的values()方法,用于返回所有的类对象
- 生成一个静态的valueOf()方法,根据name参数返回对应的类实例
一些值得关注的点
- Enum类有两个成员变量:name和ordinal。其中,name用于记录枚举常量的名字。ordinal用于记录枚举常量在声明时的顺序(从0开始)。
- Enum类有一个构造函数,它有两个入参,分别为name和ordianl赋值。
- Enum类重写了toString()方法,返回枚举常量的name值。
- Enum类重写了equals()方法,直接用等号比较。
- Enum类不允许克隆,clone()方法直接抛出异常。(保证枚举永远是单例的)
- Enum类实现了Comparable接口,直接比较枚举常量的ordinal的值。
- Enum类有一个静态的valueOf()方法,可以根据枚举类型以及name返回对应的枚举常量。
- Enum类不允许反序列化,为了保证枚举永远是单例的。