Java中的枚举类型(Enum)
Java中的枚举类型(Enum)
1 枚举类型初探
枚举类型,其语法总让人觉着怪怪的,如下:
import java.util.EnumSet;
public enum CarType {
SportCarType, JeepCarType, HatchbackCarType
/*
* Java自动给按照枚举值出现的顺序,从0开始分配了编号。
* 通过name()可以获得枚举值的名称,通过ordinal()可以获得枚举值的编号。
*/
}
这里注意如果只有SportCarType, JeepCarType, HatchbackCarType,后面没有代码可以在最后一个HatchbackCarType后不加;但是如果还有内容需要加上。
简单的一行,就定义了包含三个值的枚举类型,缺总让人觉着语法有点怪异。而在使用时:
import org.junit.Test;
public class CarTest {
@Test
public void test() {
System.out.println("SportCarType name:"+CarType.SportCarType.name());
System.out.println("SportCarType ordinal:"+CarType.SportCarType.ordinal());
System.out.println("JeepCarType name:"+CarType.JeepCarType.name());
System.out.println("JeepCarType ordinal:"+CarType.JeepCarType.ordinal());
System.out.println("HatchbackCarType name:"+CarType.HatchbackCarType.name());
System.out.println("HatchbackCarType ordinal:"+CarType.HatchbackCarType.ordinal());
}
}
就可以得到输出:
2 枚举产生之前
如果不使用枚举,我们要对车的类型这三个值分别赋予一个数字,则常见的操作为:
public class CarType{
public static final int SportCarType = 0;
public static final int JeepCarType = 1;
public static final int HatchbackCarType = 2;
}
上述方法定义十分繁琐,而且容易出错。例如我们定义的int数字出现重复,编译器也不会给出任何的警示。同时,这样的操作是实在太频繁了,最终Java 5中增加了枚举类型。
而是用枚举类型后,一切就变成了如下所示的简单几行:
public enum CarType {
SportCarType, JeepCarType, HatchbackCarType
}
而且,Java自动给按照枚举值出现的顺序,从0开始分配了编号。通过name()可以获得枚举值的名称,通过ordinal()可以获得枚举值的编号。
3 枚举实现原理
那我们定义枚举类型后,到底发生了什么呢?我们对枚举的实现原理进行探究。
首先,我们在实现CarType枚举类时,并没有定义name()和ordinal()方法。我们从这里入手,点击该方法后,发现进入了一个抽象类:
public abstract class Enum<E extends Enum<E>>
implements Comparable<E>, Serializable {}
并且,我们发现编译器不允许我们自行实现该抽象类从而构造一个新的类。但是,既然我们的CarType枚举类可以调用其中的方法,因此Season枚举类应该是继承了该抽象类。
为了验证这一猜想,我们让Season类继承一个其他的类,发现果然不可以,因为Java是不允许多继承的。
具体,我们对CarType类进行反编译
首先编译生成class文件
javac CarType.java
然后进行反编译
javap -c CarType.class
Java程序的开发过程:首先编写一个Java的代码源文件后缀.java,该源文件经过Java的编译器javac编译成一个后缀为.class的字节码文件,再由解释器java解释成本地机器码来执行。
Java反编译:就是将生成的字节码文件(后缀.class)再还原为源文件(.java)。JDK提供的反编译器为javap,是一个.exe的可执行文件
Compiled from "CarType.java"
public final class CarType extends java.lang.Enum<CarType> {
public static final CarType SportCarType;
public static final CarType JeepCarType;
public static final CarType HatchbackCarType;
public static CarType[] values();
Code:
0: getstatic #1 // Field $VALUES:[LCarType;
3: invokevirtual #2 // Method "[LCarType;".clone:()Ljava/lang/Object;
6: checkcast #3 // class "[LCarType;"
9: areturn
public static CarType valueOf(java.lang.String);
Code:
0: ldc #4 // class CarType
2: aload_0
3: invokestatic #5 // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
6: checkcast #4 // class CarType
9: areturn
static {};
Code:
0: new #4 // class CarType
3: dup
4: ldc #7 // String SportCarType
6: iconst_0
7: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V
10: putstatic #9 // Field SportCarType:LCarType;
13: new #4 // class CarType
16: dup
17: ldc #10 // String JeepCarType
19: iconst_1
20: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V
23: putstatic #11 // Field JeepCarType:LCarType;
26: new #4 // class CarType
29: dup
30: ldc #12 // String HatchbackCarType
32: iconst_2
33: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V
36: putstatic #13 // Field HatchbackCarType:LCarType;
39: iconst_3
40: anewarray #4 // class CarType
43: dup
44: iconst_0
45: getstatic #9 // Field SportCarType:LCarType;
48: aastore
49: dup
50: iconst_1
51: getstatic #11 // Field JeepCarType:LCarType;
54: aastore
55: dup
56: iconst_2
57: getstatic #13 // Field HatchbackCarType:LCarType;
60: aastore
61: putstatic #1 // Field $VALUES:[LCarType;
64: return
}
我们看到,对与枚举类,有很多值的注意的点:
- 枚举类在经过编译后确实是生成了一个扩展了java.lang.Enum的类
- 枚举类是final的,因此我们无法再继承它了
- 我们定义的每个枚举值都是该类中的一个成员,且成员的类型仍然是Season类型
- 枚举类中被默认增加了许多静态方法,例如values()等
通过这里我们可以看到,在类的static操作中,编译器帮助我们生成每个枚举值的对象。
参考:
https://blog.csdn.net/u011479200/article/details/80019827?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522164992239516780264090251%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=164992239516780264090251&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2blogtop_positive~default-1-80019827.nonecase&utm_term=java%E5%8F%8D%E7%BC%96%E8%AF%91&spm=1018.2226.3001.4450