那麼,歡呼吧!!!J2SE 5.0 beta已經發佈,其中包含瞭JSR 201 (目前處於public review狀態)的實現,JSR 201中包含瞭新的語言特性:enum,我想我應該去試試看。下面就是得到得到的結果,敢於試試看的就來吧。
深入
這裡列出瞭定義和使用枚舉類型的一個例子(取自JSR 201 文檔).
Java代碼
public class Card
{
public enum Suit {HEART, DIAMOND, CLUB, SPADE};
public enum Rank {ACE, TWO, THREE, FOUR, FIVE, SIX, SEVEN,
EIGHT, NINE, TEN, JACK, QUEEN, KING};
private final Suit suit;
private final Rank rank;
public Card(Suit suit, Rank rank); {
this.suit = suit;
this.rank = rank;
}
public Suit getSuit(); {
return suit;
}
public Rank getRank(); {
return rank;
}
public String toString(); {
return rank + " of " + suit;
}
public static void main(String… args); {
Card upMySleeve = new Card(Suit.HEART, Rank.ACE);;
System.out.println("what is up my sleeve? " + upMySleeve);;
// outputs: what is up my sleeve? ACE of HEART
}
}
Java代碼
public class Card
{
public enum Suit {HEART, DIAMOND, CLUB, SPADE};
public enum Rank {ACE, TWO, THREE, FOUR, FIVE, SIX, SEVEN,
EIGHT, NINE, TEN, JACK, QUEEN, KING};
private final Suit suit;
private final Rank rank;
public Card(Suit suit, Rank rank); {
this.suit = suit;
this.rank = rank;
}
public Suit getSuit(); {
return suit;
}
public Rank getRank(); {
return rank;
}
public String toString(); {
return rank + " of " + suit;
}
public static void main(String… args); {
Card upMySleeve = new Card(Suit.HEART, Rank.ACE);;
System.out.println("what is up my sleeve? " + upMySleeve);;
// outputs: what is up my sleeve? ACE of HEART
}
}
某些語言中,枚舉類型隻不過是披著羊皮的int。但是在上面的例子中,Suit是一個真正的class。實際上,他是java.lang.Enum的一個子類。
枚舉類型Suit經過編譯以後的代碼可能是這個樣子。實際上,枚舉類型Suit中的每一個常量都是被聲明為public static final的Suit的一個實例。
Java代碼
// This is sort of what happens.
public class Suit extends Enum {
public static final Suit HEART = new Suit("HEART", 1);;
public static final Suit DIAMOND = new Suit("DIAMOND", 2);;
public static final Suit CLUB = new Suit("CLUB", 3);;
public static final Suit SPADE = new Suit("SPADE", 4);;
public Suit(String name, int ordinal); { super(name, ordinal);;}
// some more stuff here
}
Java代碼
// This is sort of what happens.
public class Suit extends Enum {
public static final Suit HEART = new Suit("HEART", 1);;
public static final Suit DIAMOND = new Suit("DIAMOND", 2);;
public static final Suit CLUB = new Suit("CLUB", 3);;
public static final Suit SPADE = new Suit("SPADE", 4);;
public Suit(String name, int ordinal); { super(name, ordinal);;}
// some more stuff here
}
但是這不是全部,如果你仔細看看java.lang.Enum,你就會張大嘴巴,因為你會看見Enum實際上被聲明成一個泛型類Enum<E extends Enum<E>>。
我的第一反應是"這是他媽的什麼意思?” 答案在下面,但是我們要先熱熱身。
Foo<T> 的真正含義是啥米?
你的大腦神經元已經在Java 代碼List<String>和“基於String的List容器”建立瞭聯系,但是當你看到Foo<String> 這究竟是什麼意思呢?
考慮下面的代碼
T 是一個類型參數(A),其意味著Foo的class body實際上已經被某種類型(任何類型)T所參數化。1。類型T(幾乎)可以出現在class body的任何地方而不用擔心T實際上是什麼類型。
2。類型參數的語義取決於編寫類Foo的人。集合類使用類型參數來表明“這個一個T的集合”;其語義可以在javadoc中找到。對於更加通用的Foo<T>的不再是T的容器。
3。這裡真正要說的是 ,類型參數實際上允許用戶在調用函數方法的時候,不用cast就可以使用特定類型
那麼java.lang.Class<T>意味著什麼呢?
如果你查看JDK 1.5 javadoc,你就會發現java.lang.class如今有瞭一個類型參數ava.lang.Class<T>。
那麼,Class並不是Collections API,你的大腦神元經將怎麼辦呢?可以觀察Foo.class這個靜態屬性,其返回的不再是class,而是Class<Foo>。
Class的類型參數告訴用戶其究竟代表是那個類型,允許用戶在不cast的情況下就調用Class的某些方法。
以newInstance() 和cast()為例,兩者都能返回一個類型確定為T的對象。
Java代碼
Class<Date> c1 = Date.class;
Class c2 = Date.class;
Date d1 = c1.newInstance();; // 新的用法,不再有ClassCastException
Date d2 = (Date); c2.newInstance();; // 過去的用法
Object o = d1;
// 不再需要手工的cast
// 必要的時候拋出ClassCastException
Date d3 = c1.cast(o);;
// 過去的用法,需要手工cast
Date d4 = (Date); o;
Class<Date> c1 = Date.class;
Class c2 = Date.class;
Date d1 = c1.newInstance();; // new style, no potential ClassCastException
Date d2 = (Date); c2.newInstance();; // old style
Object o = d1;
// no need to do a manual cast, the cast(); method
// throws the ClassCastException if necessary
Date d3 = c1.cast(o);;
// old style, need to do a manual cast
Date d4 = (Date); o;
public class Foo<T> { // (A);
//…
}
Foo<String> f1 = …; // (B);
Foo<Integer> f2 = …; // (C);
Java代碼
Class<Date> c1 = Date.class;
Class c2 = Date.class;
Date d1 = c1.newInstance();; // 新的用法,不再有ClassCastException
Date d2 = (Date); c2.newInstance();; // 過去的用法
Object o = d1;
// 不再需要手工的cast
// 必要的時候拋出ClassCastException
Date d3 = c1.cast(o);;
// 過去的用法,需要手工cast
Date d4 = (Date); o;
Class<Date> c1 = Date.class;
Class c2 = Date.class;
Date d1 = c1.newInstance();; // new style, no potential ClassCastException
Date d2 = (Date); c2.newInstance();; // old style
Object o = d1;
// no need to do a manual cast, the cast(); method
// throws the ClassCastException if necessary
Date d3 = c1.cast(o);;
// old style, need to do a manual cast
Date d4 = (Date); o;
public class Foo<T> { // (A);
//…
}
Foo<String> f1 = …; // (B);
Foo<Integer> f2 = …; // (C);
所以,大腦神經元聯系建立完畢:Class<T>意味著 類型T的Class實例
類型參數的更多竅門
註意下面的代碼
Java代碼
abstract class Foo<SubClassOfFoo extends Foo<SubClassOfFoo>>
{
/** subclasses are forced to return themselves from this method */
public abstract SubClassOfFoo subclassAwareDeepCopy();;
}
class Bar extends Foo<Bar> {
public Bar subclassAwareDeepCopy(); {
Bar b = new Bar();;
// …
return b;
}
}
Bar b = new Bar();;
Foo<Bar> f = b;
Bar b2 = b.subclassAwareDeepCopy();;
Bar b3 = f.subclassAwareDeepCopy();; // 這裡是關鍵,父類直接返回子類的實例,而且不用Cast
Java代碼
abstract class Foo<SubClassOfFoo extends Foo<SubClassOfFoo>>
{
/** subclasses are forced to return themselves from this method */
public abstract SubClassOfFoo subclassAwareDeepCopy();;
}
class Bar extends Foo<Bar> {
public Bar subclassAwareDeepCopy(); {
Bar b = new Bar();;
// …
return b;
}
}
Bar b = new Bar();;
Foo<Bar> f = b;
Bar b2 = b.subclassAwareDeepCopy();;
Bar b3 = f.subclassAwareDeepCopy();; // 這裡是關鍵,父類直接返回子類的實例,而且不用Cast
在這裡:
1 Foo的所有subclass 都必須提供一個類型參數給Foo
2 這個類型參數必須是Foo的一個子類
3 Foo的子類把自己當作類型參數傳遞給Foo
4 Foo具有一個方法,返回SubClassOfFoo. 根據上面的條件,我們可知,對於Foo的任何子類,都必須實現subclassAwareDeepCopy(), 這個方法返回子類本身。
也就是說,我們通過這種方法,使得父類(比如Abstract Factory)可以直接把其子類的類型(而不是父類類型)作為函數的參數或者返回值來使用。
(譯者註:條件3並不是強制的,但是是必須的,例如在上例中,我們可以添加Foo的另一個子類
Java代碼
class Bar1 extends Foo<Bar> {
public Bar subclassAwareDeepCopy(); {
return new Bar();;
}
}
Java代碼
class Bar1 extends Foo<Bar> {
public Bar subclassAwareDeepCopy(); {
return new Bar();;
}
}
這裡,Bar1並不具備通過subclassAwareDeepCopy來返回自身一個實例的能力)
現在我們回過頭來看看Enum<E extends Enum<E>>
如果你明白瞭上述Foo及其子類所使用的規則,那麼再回過頭來看為什麼java.lang.Enum 被定義為Enum<E extends Enum<E>>.
E被用作getDeclaringClass()的返回值
E被用作compareTo()的參數
這意味著你可以在完成下面的代碼並且得到如下的便利a)不用強制類型轉換b) 使用Enum的子類來作為Enum方法的參數
Java代碼
Rank r = Rank.ACE;
Suit s = Suit.HEART;
r.compareTo(s);; // 語法錯誤,參數必須是Rank類型
Rank z = Enum.valueOf(Rank.class, "TWO");;//不需要經過類型轉換