说明
声明一个枚举其实很简单,直接利用enum
关键字即可,像声明一个class
一样:
public enum Season {
SPRING("Spring"),
SUMMER("Summer"),
AUTUMN("Autumn"),
WINTER("Winter");
private String description;
Season(String desc) {
this.description = desc;
}
public String getDescription() {
return description;
}
}
使用枚举有很多的好处,它避免了传统常量的无范围性,而且我们可以利用枚举实现单例模式。其实,enum
只是一个语法糖,我们使用它声明一个枚举类型, 其余事情就是 Java 编译器帮我们干的了。
使用javac
编译成class文件,再利用javap -c
将其反编译出来,得到
public final class com.yuanqixiang.service.enums.Season extends java.lang.Enum<com.yuanqixiang.service.enums.Season> {
public static final com.yuanqixiang.service.enums.Season SPRING;
public static final com.yuanqixiang.service.enums.Season SUMMER;
public static final com.yuanqixiang.service.enums.Season AUTUMN;
public static final com.yuanqixiang.service.enums.Season WINTER;
public static com.yuanqixiang.service.enums.Season[] values();
Code:
0: getstatic #1 // Field $VALUES:[Lcom/yuanqixiang/service/enums/Season;
3: invokevirtual #2 // Method "[Lcom/yuanqixiang/service/enums/Season;".clone:()Ljava/lang/Object;
6: checkcast #3 // class "[Lcom/yuanqixiang/service/enums/Season;"
9: areturn
public static com.yuanqixiang.service.enums.Season valueOf(java.lang.String);
Code:
0: ldc #4 // class com/yuanqixiang/service/enums/Season
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/yuanqixiang/service/enums/Season
9: areturn
public java.lang.String getDescription();
Code:
0: aload_0
1: getfield #7 // Field description:Ljava/lang/String;
4: areturn
static {};
Code:
0: new #4 // class com/yuanqixiang/service/enums/Season
3: dup
4: ldc #8 // String SPRING
6: iconst_0
7: ldc #9 // String Spring
9: invokespecial #10 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;)V
12: putstatic #11 // Field SPRING:Lcom/yuanqixiang/service/enums/Season;
15: new #4 // class com/yuanqixiang/service/enums/Season
18: dup
19: ldc #12 // String SUMMER
21: iconst_1
22: ldc #13 // String Summer
24: invokespecial #10 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;)V
27: putstatic #14 // Field SUMMER:Lcom/yuanqixiang/service/enums/Season;
30: new #4 // class com/yuanqixiang/service/enums/Season
33: dup
34: ldc #15 // String AUTUMN
36: iconst_2
37: ldc #16 // String Autumn
39: invokespecial #10 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;)V
42: putstatic #17 // Field AUTUMN:Lcom/yuanqixiang/service/enums/Season;
45: new #4 // class com/yuanqixiang/service/enums/Season
48: dup
49: ldc #18 // String WINTER
51: iconst_3
52: ldc #19 // String Winter
54: invokespecial #10 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;)V
57: putstatic #20 // Field WINTER:Lcom/yuanqixiang/service/enums/Season;
60: iconst_4
61: anewarray #4 // class com/yuanqixiang/service/enums/Season
64: dup
65: iconst_0
66: getstatic #11 // Field SPRING:Lcom/yuanqixiang/service/enums/Season;
69: aastore
70: dup
71: iconst_1
72: getstatic #14 // Field SUMMER:Lcom/yuanqixiang/service/enums/Season;
75: aastore
76: dup
77: iconst_2
78: getstatic #17 // Field AUTUMN:Lcom/yuanqixiang/service/enums/Season;
81: aastore
82: dup
83: iconst_3
84: getstatic #20 // Field WINTER:Lcom/yuanqixiang/service/enums/Season;
87: aastore
88: putstatic #1 // Field $VALUES:[Lcom/yuanqixiang/service/enums/Season;
91: return
}
从上面的代码可以看出:
1、定义的Season
是一个final
类型的类,继承自java.lang.Enum
2、声明了字段对应的四个 static final Season
的实例
3、实现了 values()
和 valueOf(String)
静态方法
4、static{ ... }
对所有成员进行初始化
根据以上的字节码,我们可以大致还原出Season
类的原貌:
public final class Season extends java.lang.Enum<Season> {
public static final Season SPRING;
public static final Season SUMMER;
public static final Season AUTUMN;
public static final Season WINTER;
private static final Season[] $VALUES;
private String description;
static {
SPRING = new Season("Spring", "SPRING", 0);
SUMMER = new Season("Summer", "SUMMER", 1);
AUTUMN = new Season("Autumn", "AUTUMN", 2);
WINTER = new Season("Winter", "WINTER", 3);
$VALUES = new Season[] {SPRING, SUMMER, AUTUMN, WINTER};
}
private Season(String desc, String name, int original) {
this.description = desc;
super(name, original)
}
public static Season[] values() {
return $VALUE.clone();
}
public static Season valueOf(String name) {
return Enum.valueOf(Season.class, name);
}
}
上面的代码并不是最正确的代码,只是经过java字节码推敲出来的。
了解JVM的类加载机制的朋友应该对这部分比较清楚。static
类型的属性会在类被加载之后被初始化,当一个Java类第一次被真正使用到的时候静态资源被初始化,Java类的加载和初始化过程都是线程安全的(因为虚拟机在加载枚举的类的时候,会使用ClassLoader的loadClass方法,而这个方法使用同步代码块保证了线程安全)。所以,创建一个enum类型是线程安全的。
也就是说,我们定义的一个枚举,在第一次被真正用到的时候,会被虚拟机加载并初始化,而这个初始化过程是线程安全的。而我们知道,解决单例的并发问题,主要解决的就是初始化过程中的线程安全问题。
所以,由于枚举的以上特性,枚举实现的单例是天生线程安全的。
网友评论