Enum
Enum類是java.lang包中一個類,他是Java語言中所有枚舉類型的公共基類。
一、定義
public abstract class Enum<E extends Enum<E>> implements Comparable<E>, Serializable
1.抽象類
首先,抽象類不能被實例化,所以我們在java程序中不能使用new關鍵字來聲明一個Enum,如果想要定義可以使用這樣的語法:
enum enumName{
value1,value2
method1(){}
method2(){}
}
其次,看到抽象類,第一印象是肯定有類繼承他。至少我們應該是可以繼承他的,所以:
public class testEnum extends Enum{
}
public class testEnum extends Enum<Enum<E>>{
}
public class testEnum<E> extends Enum<Enum<E>>{
}
嘗試了以上三種方式之后,得出以下結論:Enum類無法被繼承。
為什么一個抽象類不讓繼承?enum定義的枚舉是怎么來的?難道不是對Enum的一種繼承嗎?帶着這些疑問我們來反編譯以下代碼:
enum Color {RED, BLUE, GREEN}
編譯器將會把他轉成如下內容:
public final class Color extends Enum<Color> {
public static final Color[] values() { return (Color[])$VALUES.clone(); }
public static Color valueOf(String name) { ... }
private Color(String s, int i) { super(s, i); }
public static final Color RED;
public static final Color BLUE;
public static final Color GREEN;
private static final Color $VALUES[];
static {
RED = new Color("RED", 0);
BLUE = new Color("BLUE", 1);
GREEN = new Color("GREEN", 2);
$VALUES = (new Color[] { RED, BLUE, GREEN });
}
}
短短的一行代碼,被編譯器處理過之后竟然變得這么多,看來,enmu關鍵字是java提供給我們的一個語法糖啊。。。從反編譯之后的代碼中,我們發現,編譯器不讓我們繼承Enum,但是當我們使用enum關鍵字定義一個枚舉的時候,他會幫我們在編譯后默認繼承java.lang.Enum類,而不像其他的類一樣默認繼承Object類。且采用enum聲明后,該類會被編譯器加上final聲明,故該類是無法繼承的。 PS:由於JVM類初始化是線程安全的,所以可以采用枚舉類實現一個線程安全的單例模式。
2.實現Comparable和Serializable接口
Enum實現了Serializable接口,可以序列化。 Enum實現了Comparable接口,可以進行比較,默認情況下,只有同類型的enum才進行比較(原因見后文),要實現不同類型的enum之間的比較,只能復寫compareTo方法。
3.泛型:<E extends Enum<E>>
怎么理解<E extends Enum<E>>
?
首先,這樣寫只是為了讓Java的API更有彈性,他主要是限定形態參數實例化的對象,故要求只能是Enum,這樣才能對 compareTo 之類的方法所傳入的參數進行形態檢查。所以,我們完全可以不必去關心他為什么這么設計。
這里倒是可以關注一下泛型中extends的用法,以及K V O T E ? object這幾個符號之間的區別。
好啦,我們回到這個令人實在是無法理解的<E extends Enum
首先我們先來“翻譯”一下這個Enum<E extends Enum
二、屬性
在Enum中,有兩個成員變量,一個是名字(name),一個是序號(ordinal)。 序號是一個枚舉常量,表示在枚舉中的位置,從0開始,依次遞增。
private final String name;
public final String name() {
return name;
}
private final int ordinal;
public final int ordinal() {
return ordinal;
}
三、方法
1. 構造方法
前面我們說過,Enum是一個抽象類,不能被實例化,但是他也有構造函數,從前面我們反編譯出來的代碼中,我們也發現了Enum的構造函數,在Enum中只有一個保護類型的構造函數:
protected Enum(String name, int ordinal) {
this.name = name;
this.ordinal = ordinal;
}
文章開頭反編譯的代碼中private Color(String s, int i) { super(s, i); }中的super(s, i);就是調用Enum中的這個保護類型的構造函數來初始化name和ordinal。
2. 其它方法
public String toString() {
return name;
}
public final boolean equals(Object other) {
return this==other;
}
public final int hashCode() {
return super.hashCode();
}
public final int compareTo(E o) {
Enum other = (Enum)o;
Enum self = this;
if (self.getClass() != other.getClass() && // optimization
self.getDeclaringClass() != other.getDeclaringClass())
throw new ClassCastException();
return self.ordinal - other.ordinal;
}
public final Class<E> getDeclaringClass() {
Class clazz = getClass();
Class zuper = clazz.getSuperclass();
return (zuper == Enum.class) ? clazz : zuper;
}
public static <T extends Enum<T>> T valueOf(Class<T> enumType,
String name) {
T result = enumType.enumConstantDirectory().get(name);
if (result != null)
return result;
if (name == null)
throw new NullPointerException("Name is null");
throw new IllegalArgumentException(
"No enum constant " + enumType.getCanonicalName() + "." + name);
}