版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012998254/article/details/82707510
枚举实现原理
package com.own.learn.jdk.enum1;
public enum Day {
MONDAY("monday"), TUESDAY("TUESDAY"), WEDNESDAY("WEDNESDAY"),
THURSDAY("THURSDAY"), FRIDAY("FRIDAY"), SATURDAY("SATURDAY"), SUNDAY("SUNDAY");
private String name;
Day(String name) {
this.name = name;
}
}
拿出来反编译的代码:
javap -c com/own/learn/jdk/enum1/Day.class
public final class com.own.learn.jdk.enum1.Day extends java.lang.Enum<com.own.learn.jdk.enum1.Day> {
public static final com.own.learn.jdk.enum1.Day MONDAY;
public static final com.own.learn.jdk.enum1.Day TUESDAY;
public static final com.own.learn.jdk.enum1.Day WEDNESDAY;
public static final com.own.learn.jdk.enum1.Day THURSDAY;
public static final com.own.learn.jdk.enum1.Day FRIDAY;
public static final com.own.learn.jdk.enum1.Day SATURDAY;
public static final com.own.learn.jdk.enum1.Day SUNDAY;
public static com.own.learn.jdk.enum1.Day[] values();
Code:
0: getstatic #1 // Field $VALUES:[Lcom/own/learn/jdk/enum1/Day;
3: invokevirtual #2 // Method "[Lcom/own/learn/jdk/enum1/Day;".clone:()Ljava/lang/Object;
6: checkcast #3 // class "[Lcom/own/learn/jdk/enum1/Day;"
9: areturn
public static com.own.learn.jdk.enum1.Day valueOf(java.lang.String);
Code:
0: ldc #4 // class com/own/learn/jdk/enum1/Day
2: aload_0
3: invokestatic #5 // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
6: checkcast #4 // class com/own/learn/jdk/enum1/Day
9: areturn
static {};
Code:
0: new #4 // class com/own/learn/jdk/enum1/Day
3: dup
4: ldc #8 // String MONDAY
6: iconst_0
7: ldc #9 // String monday
9: invokespecial #10 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;)V
12: putstatic #11 // Field MONDAY:Lcom/own/learn/jdk/enum1/Day;
15: new #4 // class com/own/learn/jdk/enum1/Day
18: dup
19: ldc #12 // String TUESDAY
21: iconst_1
22: ldc #12 // String TUESDAY
24: invokespecial #10 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;)V
27: putstatic #13 // Field TUESDAY:Lcom/own/learn/jdk/enum1/Day;
30: new #4 // class com/own/learn/jdk/enum1/Day
33: dup
34: ldc #14 // String WEDNESDAY
36: iconst_2
37: ldc #14 // String WEDNESDAY
39: invokespecial #10 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;)V
42: putstatic #15 // Field WEDNESDAY:Lcom/own/learn/jdk/enum1/Day;
45: new #4 // class com/own/learn/jdk/enum1/Day
48: dup
49: ldc #16 // String THURSDAY
51: iconst_3
52: ldc #16 // String THURSDAY
54: invokespecial #10 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;)V
57: putstatic #17 // Field THURSDAY:Lcom/own/learn/jdk/enum1/Day;
60: new #4 // class com/own/learn/jdk/enum1/Day
63: dup
64: ldc #18 // String FRIDAY
66: iconst_4
67: ldc #18 // String FRIDAY
69: invokespecial #10 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;)V
72: putstatic #19 // Field FRIDAY:Lcom/own/learn/jdk/enum1/Day;
75: new #4 // class com/own/learn/jdk/enum1/Day
78: dup
79: ldc #20 // String SATURDAY
81: iconst_5
82: ldc #20 // String SATURDAY
84: invokespecial #10 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;)V
87: putstatic #21 // Field SATURDAY:Lcom/own/learn/jdk/enum1/Day;
90: new #4 // class com/own/learn/jdk/enum1/Day
93: dup
94: ldc #22 // String SUNDAY
96: bipush 6
98: ldc #22 // String SUNDAY
100: invokespecial #10 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;)V
103: putstatic #23 // Field SUNDAY:Lcom/own/learn/jdk/enum1/Day;
106: bipush 7
108: anewarray #4 // class com/own/learn/jdk/enum1/Day
111: dup
112: iconst_0
113: getstatic #11 // Field MONDAY:Lcom/own/learn/jdk/enum1/Day;
116: aastore
117: dup
118: iconst_1
119: getstatic #13 // Field TUESDAY:Lcom/own/learn/jdk/enum1/Day;
122: aastore
123: dup
124: iconst_2
125: getstatic #15 // Field WEDNESDAY:Lcom/own/learn/jdk/enum1/Day;
128: aastore
129: dup
130: iconst_3
131: getstatic #17 // Field THURSDAY:Lcom/own/learn/jdk/enum1/Day;
134: aastore
135: dup
136: iconst_4
137: getstatic #19 // Field FRIDAY:Lcom/own/learn/jdk/enum1/Day;
140: aastore
141: dup
142: iconst_5
143: getstatic #21 // Field SATURDAY:Lcom/own/learn/jdk/enum1/Day;
146: aastore
147: dup
148: bipush 6
150: getstatic #23 // Field SUNDAY:Lcom/own/learn/jdk/enum1/Day;
153: aastore
154: putstatic #1 // Field $VALUES:[Lcom/own/learn/jdk/enum1/Day;
157: return
}
转换成代码 大概是这样的:
package com.own.learn.jdk.enum1;
public final class DayEnum extends Enum {
public static DayEnum MONDAY;
public static DayEnum TUESDAY;
public static DayEnum WEDNESDAY;
public static DayEnum THURSDAY;
public static DayEnum FRIDAY;
public static DayEnum SATURDAY;
public static DayEnum SUNDAY;
private static DayEnum $VALUES[];
static {
MONDAY = new DayEnum("MONDAY", 0);
TUESDAY = new DayEnum("TUESDAY", 1);
WEDNESDAY = new DayEnum("WEDNESDAY", 2);
THURSDAY = new DayEnum("THURSDAY", 3);
FRIDAY = new DayEnum("FRIDAY", 4);
SATURDAY = new DayEnum("SATURDAY", 5);
SUNDAY = new DayEnum("SUNDAY", 6);
$VALUES = (new DayEnum[]{
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
});
}
public DayEnum[] values() {
return (DayEnum[]) $VALUES.clone();
}
public DayEnum valueOf(String name) {
return (DayEnum) Enum.valueOf(com.own.learn.jdk.enum1.DayEnum.class, name);
}
protected DayEnum(String name, int ordinal) {
super(name, ordinal);
}
@Override
public String toString() {
return super.toString();
}
}
Enum类
public abstract class Enum<E extends Enum<E>>
implements Comparable<E>, Serializable {
private final String name;
public final String name() {
return name;
}
private final int ordinal;
public final int ordinal() {
return ordinal;
}
protected Enum(String name, int ordinal) {
this.name = name;
this.ordinal = ordinal;
}
public String toString() {
return name;
}
public final boolean equals(Object other) {
return this == other;
}
public final int hashCode() {
return super.hashCode();
}
protected final Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
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;
}
@SuppressWarnings("unchecked")
public final Class<E> getDeclaringClass() {
Class<?> clazz = getClass();
Class<?> zuper = clazz.getSuperclass();
return (zuper == Enum.class) ? (Class<E>) clazz : (Class<E>) zuper;
}
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);
}
/**
* enum classes cannot have finalize methods.
*/
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");
}
}
- ordinal: 从0到Integer.Max_value的数字,只在EnumSet和EnumMap使用,默认是0.
- equals方法:`return this==other。枚举是常量
- compareTo:默认比较的是:ordinal
- valueOf:
enumType.enumConstantDirectory().get(name);
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;
}
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;
}
private volatile transient T[] enumConstants = null;
通过反射调用values方法得到枚举的数组,然后转成map
枚举的进阶用法
向enum类添加方法与自定义构造函数
public enum Day {
MONDAY("monday"), TUESDAY("TUESDAY"), WEDNESDAY("WEDNESDAY"),
THURSDAY("THURSDAY"), FRIDAY("FRIDAY"), SATURDAY("SATURDAY"), SUNDAY("SUNDAY");
private String name;
Day(String name) {
this.name = name;
}
}
enum类中定义抽象方法
package com.own.learn.jdk.enum1;
public enum DayAbstractMethod {
FOOD {
@Override
public void printName() {
System.out.println(" name is " + name());
}
};
public abstract void printName();
public static void main(String[] args) {
DayAbstractMethod.FOOD.printName();
}
}
enum类与接口
package com.own.learn.jdk.enum1;
interface Start{
void start();
}
interface End{
void end();
}
public enum EnumInterface implements Start, End{
TEST1
;
@Override
public void start() {
}
@Override
public void end() {
}
}
与单例模式
public enum EnumSingleton {
private enum MyEnumSingleton{
INSTANCE;
private Resource resource;
private MyEnumSingleton(){
resource = new Resource();
}
public Resource getResource(){
return resource;
}
}
public static Resource getResource(){
return MyEnumSingleton.INSTANCE.getResource();
}
}
多线程环境下的安全性
这个特性上面已经介绍了,因为INSTANCE最后会被编译器处理成static final的,并且在static模块中进行的初始化,因此它的实例化是在class被加载阶段完成,是线程安全的。这个特性也决定了枚举单例不是lazy的,如果你的单例初始化比较费时且大多数情况下只会被引用但是不会被真正调用的话,你需要使用lazy的单例模式(上面传统单例的方法二实现),而不要选择枚举单例。
不可被反射实例化
在Java中,不仅通过限制enum只能声明private的构造方法来防止Enum被使用new进行实例化,而且还限制了使用反射的方法不能通过Constructor来newInstance一个枚举实例。
序列化的唯一性
在序列化和反序列化的时候Enum的处理是和其他类不同的,在序列化的时候实际上只写入了Enum的name成员,而没有保存ordinal成员;在反序列化的时候从ObjectInputStream中读取Enum的name成员,同时调用Enum的valueof方法传入读取的name得到对应的ordinal值。同时Enum是不支持自定义序列化和反序列化的,一些序列化和反序列化对应的函数例如readObject和writeObject及serialVersionUID等属性在Enum的序列化过程中都是被忽略的。
Enum在序列化和反序列化上的特性保证了使用Enum来实现单例是经受得起序列化的攻击的。