在 有了enum之後 中使用enum定義過以下的Action列舉型態:
public enum Action {
STOP, RIGHT, LEFT, UP, DOWN
}
STOP, RIGHT, LEFT, UP, DOWN
}
在當時談過,enum定義了特殊的類別,繼承自java.lang.Enum,不過這是由編譯器處理,直接撰寫程式繼承Enum類別會被編譯器拒絕,即便如此,想要瞭解列舉型態如何定義與運用,先瞭解Enum類別是必要的。首先看到Enum的class定義:
public abstract class Enum<E extends Enum<E>>
implements Comparable<E>, Serializable {
...
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;
}
...
}
implements Comparable<E>, Serializable {
...
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;
}
...
}
Enum是個抽象類別,無法直接實例化,它實作了Comparable介面,在compareTo()方法中,主要是針對ordinal成員比較,也就是在需要排序Enum實例的場合,是依據ordinal成員進行排序。ordinal成員值是在Enum建構式中設定:
...略
private final String name;
private final int ordinal;
protected Enum(String name, int ordinal) {
this.name = name;
this.ordinal = ordinal;
}
public final String name() {
return name;
}
public String toString() {
return name;
}
public final int ordinal() {
return ordinal;
}
...略
還記得 有了enum之後 中曾列出Action.class反編譯後的內容嗎?以下再更詳細列出反編譯後的結果:
public final class Action extends Enum {
public static Action[] values() {
return (Action[])\$VALUES.clone();
}
public static Action valueOf(String s) {
return (Action)Enum.valueOf(Action, s);
}
private Action(String s, int i) {
super(s, i);
}
public static final Action STOP;
public static final Action RIGHT;
public static final Action LEFT;
public static final Action UP;
public static final Action DOWN;
略...
static {
STOP = new Action("STOP", 0);
RIGHT = new Action("RIGHT", 1);
LEFT = new Action("LEFT", 2);
UP = new Action("UP", 3);
DOWN = new Action("DOWN", 4);
略...
}
}
Action的建構式被宣告為private,因此只能在Action類別中呼叫,呼叫建構式時,會傳入代表Action列舉成員的名稱字串與int值, 而在Action建構式中呼叫了super(),因此列舉成員的名稱字串與int值會分別設定給Enum的name與ordinal成員,因此 ordinal的值,會是使用enum列舉的成員順序,數值由0開始。
可以透過Enum定義的name()方法取得列舉成員名稱字串,這適用於需要使用字串代表列舉值的場合,相當於toString()的作用,事實上 toString()也只是傳回name成員的值;可透過ordinal()取得列舉int值,這適用於需要使用int代表列舉值的場合。例如在JDK 1.4之前撰寫的API,仍是使用interface定義常數作為列舉值,在使用enum定義列舉之後,若仍想與這些舊API合作,就可以呼叫Enum實 例的ordinal()方法。例如 沒有enum之前 的Game類別,可以如下操作:
- GameDemo.java
package cc.openhome;
public class GameDemo {
public static void main(String[] args) {
Game.play(Action.DOWN.ordinal());
Game.play(Action.RIGHT.ordinal());
}
}
- Action.java
package cc.openhome;
public enum Action {
STOP, RIGHT, LEFT, UP, DOWN
}
switch比對時可以使用Enum型態,實際上也是利用了Enum的ordinal()取得int值。
Enum的valueOf()方法,可以傳入字串與Enum實例,它會傳回對應的列舉實例。例如以下會顯示true:
Action action = Enum.valueOf(Action.class, "UP");
System.out.println(Action.UP == action);
不過通常會透過Enum子類別的valueOf()方法,其內部就使用了Enum.valueOf()(可觀察先前反編譯Action列舉的程式碼)。例如以下會顯示true:
Action action = Action.valueOf("UP");
System.out.println(Action.UP == action);
Enum的equals()與hashCode()基本上繼承了Object的行為,但被標示為final:
...略
public final boolean equals(Object other) {
return this==other;
}
public final int hashCode() {
return super.hashCode();
}
...略
由於標示為final,所以定義列舉時,不能重新實作equals()與hashCode(),這是因為列舉成員,在JVM中只會存在單一實例,Object定義的equals()與hashCode()作為物件相等性比較是適當的定義。