2025-05-23

 

那麼,歡呼吧!!!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");;//不需要經過類型轉換   

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *