目录
  1. 1. Enum源码解析
    1. 1.1. 类定义
    2. 1.2. 主要变量
    3. 1.3. 构造方法
    4. 1.4. 主要方法
      1. 1.4.1. name 和 ordinal
      2. 1.4.2. toString、equals和hashCode
      3. 1.4.3. clone
      4. 1.4.4. compareTo
      5. 1.4.5. getDeclaringClass
      6. 1.4.6. valueOf
      7. 1.4.7. finalize和反序列化
Enum源码解析

Enum源码解析

类定义

1
2
public abstract class Enum<E extends Enum<E>>
implements Comparable<E>, Serializable

Enum是一个抽象类,其泛型是其子类,也就是自己定义的枚举类型

主要变量

1
2
3
4
5
6
// 用于保存定义的枚举常量的名称;大多数程序员应该使用toString方法而不是直接访问此字段
private final String name;

// 枚举常量的序数,(它在枚举声明中的位置,其中初始常量的序数为零)
// 大多数程序员都不会使用这个领域.它设计用于复杂的基于枚举的数据结构
private final int ordinal;

构造方法

1
2
3
4
5
6
7
8
/**
* 唯一的构造函数,protected修饰使用者无法调用
* 它由编译器发出的代码用于响应枚举类型声明
*/
protected Enum(String name, int ordinal) {
this.name = name;
this.ordinal = ordinal;
}

主要方法

name 和 ordinal

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/*
* 返回此枚举常量的名称,与其枚举声明中声明的完全相同
* 大多数程序员应优先使用toString方法,因为toString方法可能返回一个更加用户友好的名称.方法主要用于特殊情况,
其中正确性取决于获取确切名称,该名称在不同版本之间不会有所不同.
*/
public final String name() {
return name;
}

/*
* 返回此枚举常量的序数(它在枚举声明中的位置,其中初始常量的序数为零)
* 大多数程序员都没有使用这种方法,它设计用于复杂的基于枚举的数据结构;例如java.util.EnumSet和java.util.EnumMap
*/
public final int ordinal() {
return ordinal;
}

toString、equals和hashCode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* 返回声明中包含的此枚举常量的名称
* 可以覆盖该方法,但通常不需要.当存在更"程序员友好"的字符串形式时,枚举类型应该重写此方法
*/
public String toString() {
return name;
}

/**
* 如果指定的对象等于此枚举常量,则返回true。
*/
public final boolean equals(Object other) {
return this==other;
}

/**
* 返回此枚举常量的哈希码
*/
public final int hashCode() {
return super.hashCode();
}

clone

1
2
3
4
5
6
7
/**
* 抛出CloneNotSupportedException。
* 这保证了枚举永远不会被克隆,这是保持其"单身"状态所必需的。
*/
protected final Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}

compareTo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* 将此枚举与指定的订单对象进行比较。
* 返回负整数,零或正整数,因为此对象小于,等于或大于指定对象。
*
* 枚举常量仅与同一枚举类型的其他枚举常量相当。
* 此方法实现的自然顺序是声明常量的顺序。
*/
public final int compareTo(E o) {
Enum<?> other = (Enum<?>)o;
Enum<E> self = this;
if (self.getClass() != other.getClass() && // optimization
self.getDeclaringClass() != other.getDeclaringClass())
throw new ClassCastException();
return self.ordinal - other.ordinal;
}

getDeclaringClass

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* 返回与此枚举常量的枚举类型相对应的Class对象
* 当且仅当e1.getDeclaringClass()== e2.getDeclaringClass()时,
* 两个枚举常量e1和e2具有相同的枚举类型。
* (此方法返回的值可能与使用常量特定类体的枚举常数Object.getClass()方法返回的值不同)
*
* @return 该类对象对应于此枚举常量的枚举类型
*/
@SuppressWarnings("unchecked")
public final Class<E> getDeclaringClass() {
Class<?> clazz = getClass();
Class<?> zuper = clazz.getSuperclass();
return (zuper == Enum.class) ? (Class<E>)clazz : (Class<E>)zuper;
}

valueOf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
/**
* 根据范型类型和名称获得这个枚举的实例
* 实际通过Class类中的方法获取枚举值:enumType.enumConstantDirectory().get(name);
* 其中enumType是Class类型的对象,name是枚举对象的名称
*/
public static <T extends Enum<T>> T valueOf(Class<T> enumType,
String name) {
T result = enumType.enumConstantDirectory().get(name);
if (result != null)
return result;
if (name == null)
throw new NullPointerException("Name is null");
throw new IllegalArgumentException("No enum constant " + enumType.getCanonicalName() + "." + name);
}

/**
* Class类中维护了一个枚举名称和实例变量的map:
* private volatile transient Map<String, T> enumConstantDirectory = null;
* 如果这个类是一个枚举类型,那么在枚举类第一次访问valueof方法时,会生成这个map
*/
Map<String, T> enumConstantDirectory() {
if (enumConstantDirectory == null) {
T[] universe = getEnumConstantsShared();
if (universe == null)
throw new IllegalArgumentException(
getName() + " is not an enum type");
Map<String, T> m = new HashMap<>(2 * universe.length);
for (T constant : universe)
m.put(((Enum<?>)constant).name(), constant);
enumConstantDirectory = m;
}
return enumConstantDirectory;
}

枚举类型的Class时如何获得保存的枚举值的?
;
/**
* Class维护了一个枚举类型的数组:private volatile transient T[] enumConstants = null
* 然后通过调用枚举类中的values方法,将枚举数据赋值给这个变量
*/
T[] getEnumConstantsShared() {
if (enumConstants == null) {
if (!isEnum()) return null;
try {
final Method values = getMethod("values");
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<Void>() {
public Void run() {
values.setAccessible(true);
return null;
}
});
@SuppressWarnings("unchecked")
T[] temporaryConstants = (T[])values.invoke(null);
enumConstants = temporaryConstants;
}
// These can happen when users concoct enum-like classes
// that don't comply with the enum spec.
catch (InvocationTargetException | NoSuchMethodException |
IllegalAccessException ex) { return null; }
}
return enumConstants;
}

通过枚举类型生成的values方法,可以获得所有的枚举值。
查看反编译代码可以看到枚举类中会生成一个values方法。静态方法invoke参数为null

finalize和反序列化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* 枚举类不能有finalize方法
*/
protected final void finalize() { }

/**
* 防止默认反序列化
*/
private void readObject(ObjectInputStream in) throws IOException,
ClassNotFoundException {
throw new InvalidObjectException("can't deserialize enum");
}

private void readObjectNoData() throws ObjectStreamException {
throw new InvalidObjectException("can't deserialize enum");
}
文章作者: Eric Liang
文章链接: https://ericql.github.io/2019/11/12/01-Java%E5%9F%BA%E7%A1%80%E7%AF%87/02-JDK%E6%BA%90%E7%A0%81%E7%AF%87/Enum%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Eric Liang
打赏
  • 微信
  • 支付宝