枚举类型是什么呢,其实是指一组固定的常量组成合法值的类型。
java中如何定义,看下面代码:
public enum EnumDemo {
A, B
}
这就是枚举类型。我们知道,java面向对象的语言,不就是对象和类吗,这enum是什么东西?其实这是java语法,是编译器优化,看下面,javap后的汇编:
public final class com.common.EnumDemo extends java.lang.Enum<com.common.EnumDemo> {
public static final com.common.EnumDemo A; //2个本类的实例,并且是静态final域
public static final com.common.EnumDemo B;
static {};
Code:
0: new #1 // class com/common/EnumDemo
3: dup
4: ldc #13 // String A
6: iconst_0 //下面是调用父类构造方法进行初始化
7: invokespecial #14 // Method "<init>":(Ljava/lang/String;I)V
10: putstatic #18 // Field A:Lcom/common/EnumDemo;//赋值给静态域A
13: new #1 // class com/common/EnumDemo 下面同样赋值静态域B
16: dup
17: ldc #20 // String B
19: iconst_1
20: invokespecial #14 // Method "<init>":(Ljava/lang/String;I)V
23: putstatic #21 // Field B:Lcom/common/EnumDemo;
26: iconst_2 //常量2入栈,实例化数组
27: anewarray #1 // class com/common/EnumDemo
30: dup
31: iconst_0
32: getstatic #18 // Field A:Lcom/common/EnumDemo;
35: aastore //把A赋值给数组第一个元素,下面的是赋值个第二个元素
36: dup
37: iconst_1
38: getstatic #21 // Field B:Lcom/common/EnumDemo;
41: aastore
42: putstatic #23 // Field ENUM$VALUES:[Lcom/common/EnumDemo;
45: return
public static com.common.EnumDemo[] values(); //此方法是获取静态代码块中生成的枚举类型数组
Code:
0: getstatic #23 // Field ENUM$VALUES:[Lcom/common/EnumDemo;
3: dup
4: astore_0
5: iconst_0
6: aload_0
7: arraylength
8: dup
9: istore_1
10: anewarray #1 // class com/common/EnumDemo
13: dup
14: astore_2
15: iconst_0
16: iload_1
17: invokestatic #31 // Method java/lang/System.arraycopy:(Ljava/lang/Object;ILjava/lang/Object;II)V
20: aload_2
21: areturn
public static com.common.EnumDemo valueOf(java.lang.String);
Code:
0: ldc #1 // class com/common/EnumDemo
2: aload_0
3: invokestatic #39 // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
6: checkcast #1 // class com/common/EnumDemo
9: areturn
}
发现没,其实枚举也是类,并且还继承了java.lang.Enum。由汇编可以看出,枚举的初始化过程是在静态代码块中进行,我们知道,静态代码块只在类首次加载的时候执行一次,final域保证引用地址不会改变。同时,我们也没有看到有公有的构造方法,客户端也就不能创建新的实例,由此可见,枚举类型具有实例受限的特性。
实例受限,很容易让我们想到一种设计模式。没错,就是单例。接下来我们我如何用枚举实现单例。
public enum EnumDemo {
A;
public void doSomeThing() {
System.out.println("dosomething");
}
public static void main(String[] args) {
EnumDemo.A.doSomeThing();
}
}
看代码,就是这么简单,实例唯一,就是单例,什么线程安全,什么双重检验,什么懒汉饿汉模式,都不用考虑,枚举天然的适合做为单例。这也是Effective Java推崇的做法。
可能有些人用枚举来表示状态,但是需要用数字表示,好存入数据库,这个也简单,只需要为这个类加个属性就ok了,看代码。
public enum EnumDemo {
A(2), B(4);
private int status;
private EnumDemo(int status) {
this.status = status;
}
public int getStatus() {
return status;
}
public static void main(String[] args) {
System.out.println(EnumDemo.A.getStatus());
System.out.println(EnumDemo.B.getStatus());
}
}
运行,打印
2
4
由此可见,用枚举来做常量,会非常直观,也非常的安全,因为有类型安全校验的保证,不会如同int类型的枚举一样,随便一个数字都能进行常量替换。这种怪异的写法,确实不好理解,尤其是有额外的属性后,这就需要熟能生巧了,自己javap慢慢研究。