枚举类型的基本使用
枚举类是和class一样的java关键字
,用来定义枚举类的
为什么定义的枚举类,可以单独定义和直接使用,不需要实例化?这需要探究它的内部原理
定义和使用一个枚举
public class enumdemos1 {
public enum EnumDemo1 {
A,B,C,D,E
}
public static void main(String[] args) {
EnumDemo1 a = EnumDemo1.A;
System.out.println(a);
System.out.println(EnumDemo1.A);
System.out.println(Arrays.asList(EnumDemo1.values()));
System.out.println(EnumDemo1.valueOf(String.valueOf(EnumDemo1.B)));
System.out.println(EnumDemo1.B.ordinal());
}
}
Enum类的常用方法
values() 以数组形式返回枚举类型的所有成员
valueOf() 将普通字符串转换为枚举实例
compareTo() 比较两个枚举成员在定义时的顺序
ordinal() 获取枚举成员的索引位置
枚举的原理
通过字节码看enum背后执行的操作
public enum EnumDemo1 {
A,
B,
C,
D;
private EnumDemo1() {
}
}
Compiled from "EnumDemo1.java"
public final class src.Temun.EnumDemo1 extends java.lang.Enum<src.Temun.EnumDemo1> {
public static final src.Temun.EnumDemo1 A;
public static final src.Temun.EnumDemo1 B;
public static final src.Temun.EnumDemo1 C;
public static final src.Temun.EnumDemo1 D;
public static src.Temun.EnumDemo1[] values();
Code:
0: getstatic #1 // Field $VALUES:[Lsrc/Temun/EnumDemo1;
3: invokevirtual #2 // Method "[Lsrc/Temun/EnumDemo1;".clone:()Ljava/lang/Object;
6: checkcast #3 // class "[Lsrc/Temun/EnumDemo1;"
9: areturn
public static src.Temun.EnumDemo1 valueOf(java.lang.String);
Code:
0: ldc #4 // class src/Temun/EnumDemo1
2: aload_0
3: invokestatic #5 // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
6: checkcast #4 // class src/Temun/EnumDemo1
9: areturn
static {};
Code:
0: new #4 // class src/Temun/EnumDemo1
3: dup
4: ldc #7 // String A
6: iconst_0
7: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V
10: putstatic #9 // Field A:Lsrc/Temun/EnumDemo1;
13: new #4 // class src/Temun/EnumDemo1
16: dup
17: ldc #10 // String B
19: iconst_1
20: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V
23: putstatic #11 // Field B:Lsrc/Temun/EnumDemo1;
26: new #4 // class src/Temun/EnumDemo1
29: dup
30: ldc #12 // String C
32: iconst_2
33: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V
36: putstatic #13 // Field C:Lsrc/Temun/EnumDemo1;
39: new #4 // class src/Temun/EnumDemo1
42: dup
43: ldc #14 // String D
45: iconst_3
46: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V
49: putstatic #15 // Field D:Lsrc/Temun/EnumDemo1;
52: iconst_4
53: anewarray #4 // class src/Temun/EnumDemo1
56: dup
57: iconst_0
58: getstatic #9 // Field A:Lsrc/Temun/EnumDemo1;
61: aastore
62: dup
63: iconst_1
64: getstatic #11 // Field B:Lsrc/Temun/EnumDemo1;
67: aastore
68: dup
69: iconst_2
70: getstatic #13 // Field C:Lsrc/Temun/EnumDemo1;
73: aastore
74: dup
75: iconst_3
76: getstatic #15 // Field D:Lsrc/Temun/EnumDemo1;
79: aastore
80: putstatic #1 // Field $VALUES:[Lsrc/Temun/EnumDemo1;
83: return
}
从字节码可以看出
- enum最后被转为
继承了extends java.lang.Enum<src.Temun.EnumDemo1>
的final不可以继承的类
- enum生成的类的类名就是枚举类的类名
- enum里定义的变量A,B,C,D都被
实例化为了为了静态的枚举类对象,在static代码块里被初始化
,总结:
枚举类本质上也是一个普通的类,可以里面正常的定义方法和初始化函数等等
而枚举类中定义的成员,比如上面代码里的A,B,C,D其实是这个枚举类实例化的静态对象
因为是静态对象,所以可以直接获取到,又因为实例化了,所以可以调用枚举类内部自定义的方法。
因为对象会被实例化,可以调用定义的初始化函数,而且会把enum类中定义的一些非静态方法转为对象的内部方法,对象在声明的时候也可以自定义自己专属方法
枚举内部会自动生成两个静态的枚举方法(values,valueOf)
枚举的静态方法数据类对象的,通过类直接调用
枚举类就是一个普通的类,不同的是可以直接写几个值用来替代生成这个类的静态对象的过程,
因此是一种定义类并在类中实例化静态对象的语法糖
单例模式下使用枚举类型
利用了枚举的对象是静态对象(准确的说应该是:类的静态字段),在jvm的类的静态变量初始化的时候使用了clinit()方法进行了初始化,这个方法是线程安全的
class User {
//私有化构造函数
private User(){ }
//定义一个静态枚举类
static enum SingletonEnum{
//创建一个枚举对象,该对象天生为单例
INSTANCE;
private User user;
//私有化枚举的构造函数
private SingletonEnum(){
user=new User();
}
public User getInstnce(){
return user;
}
}
//对外暴露一个获取User对象的静态方法
public static User getInstance(){
return SingletonEnum.INSTANCE.getInstnce();
}
}
public class Test {
public static void main(String [] args){
System.out.println(User.getInstance());
System.out.println(User.getInstance());
System.out.println(User.getInstance()==User.getInstance());
}
}
枚举集合EnumMap和EnumSet
枚举集合和普通的集合相同,就是键值k为枚举类型罢了
简单的例子,参考使用即可
public static void main(String[] args) throws Exception {
EnumMap<Season, String> map = new EnumMap<>(Season.class);
map.put(Season.FALL, "硕果累累的秋天");
map.put(Season.WINTER, "寒风凛冽的冬天");
System.out.println(map.get(Season.FALL));
}