标签:
Java1.5之前是没有枚举的,如果想使用类似枚举的特性,也即是需要使用常量的时候,可以通过如下代码完成:
Java中的常量定义:
publicclassSex2 {
publicstaticfinalintGIRL = 1;
publicstaticfinalintBOY = 2;
publicstaticvoid main(String[]args) {
System.out.println(Sex2.GIRL);
}
}
但是这样做有个缺点,就是不够直观,我们打印出Sex2.GIRL,看到的却是数字1。于是我们有了下面的改进:
改进一:
publicclassSex3 {
publicstaticfinal StringGIRL ="GIRL";
publicstaticfinal StringBOY ="BOY";
publicstaticvoid main(String[]args) {
System.out.println(Sex3.GIRL);
}
}
现在就比较直观了,我们打印出Sex3.GIRL,就能看到是GIRL,意思十分明确。可是问题又来了,如果我有一个方法接受GIRL或BOY为参数,但是我不能保证别人调用方法时使用别的字符串,比如“KID”。于是我们又有了进一步的改进:
改进二:
publicclassSex4 {
publicstaticfinal Sex4GIRL =new Sex4("GIRL");
publicstaticfinal Sex4BOY =new Sex4("GIRL");
private Stringsex;
private Sex4(Stringsex){
this.sex =sex;
}
public String toString(){
returnsex;
}
}
这样在需要使用性别的地方,就可以通过使用Sex4这个类型来保证性别时能是BOY或者GIRL了。比如类似如下函数的定义:
publicvoidoutSex(Sex4sex){
System.out.println(sex);
}
但是现在问题又来了,我们只是要使用两个常量,但是却要写那么多行代码(定义Sex4的时候),有没有简单的做法呢?答案当然是有,为了简化我们的代码书写,Java enum类型横空出世,下面的代码跟上面Sex4的定义是等效的:
改进三,enum类型横空出世:
publicenumSexEnum {
GIRL,
BOY
}
我的天!简直不敢相信,真是太简洁了!那需要使用他的地方该如何定义呢:
publicvoidoutSex(SexEnumsex){
System.out.println(sex);
}
疑问:既然Java1.5之前没有enum,那么1.5多出来的enum到底是什么东西?他跟一个普通的类有什么不同呢?
告诉你吧,实际上Java 中的enum就是就是类,定义了一个enum就是定义了一个类,对SexEnum.class的反编译印证了这一点。
javap -p SexEnum.class
Compiled from "SexEnum.java"
public final class SexEnum extendsjava.lang.Enum<SexEnum> {
public static final SexEnum GIRL;
public static final SexEnum BOY;
private static final SexEnum[] $VALUES;
public static SexEnum[] values();
public static SexEnum valueOf(java.lang.String);
private SexEnum();
static {};
}
我们看到SexEnum是一个被final修饰的类,继承自java.lang.Enum。还看到除了我们自己定义的GIRL和BOY成员之外,类里面还多了四个成员和一个静态代码块。请注意构造方法是私有的!你可能已经猜到了,这里的继承关系,及这些成员是编译器帮我们加上的。通过反编译可以看到这些成员函数以及静态代码块对应的JVM字节码:
javap -c SexEnum.class
Compiled from "SexEnum.java"
public final class SexEnum extendsjava.lang.Enum<SexEnum> {
public static final SexEnum GIRL;
public static final SexEnum BOY;
public static SexEnum[] values();
Code:
0: getstatic #1 // Field $VALUES:[LSexEnum;
3: invokevirtual #2 // Method "[LSexEnum;".clone:()Ljava/lang/Object;
6: checkcast #3 // class"[LSexEnum;"
9: areturn
public static SexEnum valueOf(java.lang.String);
Code:
0: ldc #4 // class SexEnum
2: aload_0
3: invokestatic #5 // Methodjava/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
6: checkcast #4 // class SexEnum
9: areturn
static {};
Code:
0: new #4 // class SexEnum
3: dup
4: ldc #7 // String GIRL
6: iconst_0
7: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V
10: putstatic #9 // Field GIRL:LSexEnum;
13: new #4 // class SexEnum
16: dup
17: ldc #10 // String BOY
19: iconst_1
20: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V
23: putstatic #11 // Field BOY:LSexEnum;
26: iconst_2
27: anewarray #4 // class SexEnum
30: dup
31: iconst_0
32: getstatic #9 // Field GIRL:LSexEnum;
35: aastore
36: dup
37: iconst_1
38: getstatic #11 // Field BOY:LSexEnum;
41: aastore
42: putstatic #1 // Field $VALUES:[LSexEnum;
45: return
}
很明显,静态代码块对应的代码完成了对成员GIRL和BOY的初始化工作。好久没有看过JVM字节码,都忘光了,想明白上字节码的语义,请自行阅读《Java虚拟机说明书》
结论:通过定义枚举,可以保证需要使用该枚举的地方,参数一定是该枚举的成员,同时增强代码的可读性。enum不过是Java语言为我们提供的一个语法糖[1](什么是语法糖?),方便我们定义常量。通过enum关键字定义的实际上是一个类,只不过编译器会保证这个类继承自Enum,并且会给这个类自动的加入一些成员。
[1] 语法糖:就是在编译器层面对Java语法的改动,并没有改动JVM,即字节码的结构并没有改变。Java中的语法糖还有:泛型,增强的for等。
个人的浅薄理解,欢迎转载,转载注明出处http://blog.csdn.net/u014495327/article/details/42043823。by hoolee。
标签:
原文地址:http://blog.csdn.net/u014495327/article/details/42043823