Enum 奇怪的泛型 自限定泛型 循環泛型


come from http://www.it165.net/pro/html/201305/5643.html

  • public abstract class Enum<E extends Enum<E>>
    extends Object
    implements Comparable<E>, Serializable

    為什么 Enum 類需要使用如下這么奇怪的泛型,<E extends Enum<E>>,初次看真是讓我暈了, E 到底代表什么啊?為什么不定義成 public abstract class Enum extends Object 呢?很容易找到答案,Enum 需要實現Comparable 比較接口。

    那似乎也可以定義成 public abstract class Enum<E>extends Object implements Comparable<E>, Serializable 。仔細想,就會發現會有問題,Comparable 的compareTo()方法是這樣的: public final int compareTo(E o),我們肯定不希望這個 E 是任何類型的,而是希望這個E 是 Enum 類型的,同時我們不希望兩個不同的 Enum 子類實例可以進行比較(沒有意義),即我們最希望的是同一個 Enum 子類的實例進行比較。
     
    下面 的 EnumClass.java 摘自 《Thinking in java 》第19章枚舉類型,稍微修改了下。通過 javap javap Shrubbery 反編譯,可以看到 Shrubbery 是一個繼承自 Enum 的類。


     

    01. Compiled from "EnumClass.java"
    02. final class enumerated.Shrubbery extends java.lang.Enum{
    03. public static final enumerated.Shrubbery GROUND;
    04. public static final enumerated.Shrubbery CRAWLING;
    05. public static final enumerated.Shrubbery HANGING;
    06. static {};
    07. public static enumerated.Shrubbery[] values();
    08. public static enumerated.Shrubbery valueOf(java.lang.String);
    09. }

    由於擦除的原因, enum Shrubbery {} 實事上等價於 final class Shrubbery extends Enum<Shrubbery>(即告訴編譯器Shrubbery 繼承於 Enum,而這個Enum 的泛型參數就是 Shrubbery 自身)。現在我們檢查下,Shrubbery 符不符合 <E extends Enum<E>> 形式,如果你還看不明白,可以把 E 替換成Shrubbery ,你可以看到這就是 Shrubbery 的類定義,所以Shrubbery 完全符合要求!另外編譯加上 final 修飾的原因是不希望 Enum 的子類可以作為父類被其它類繼承。

     

    01. //: enumerated/EnumClass.java
    02. // Capabilities of the Enum class
    03. package enumerated;
    04. import static net.mindview.util.Print.*;
    05.  
    06. enum Shrubbery { GROUND, CRAWLING, HANGING }
    07.  
    08. // 錯誤無法繼承
    09. //enum ShrubberySub extends Shrubbery {};
    10. enum AnotherShrubbery{GROUND, CRAWLING, HANGING }
    11.  
    12. public class EnumClass {
    13. public static void main(String[] args) {
    14. for(Shrubbery s : Shrubbery.values()) {
    15. print(s + " ordinal: " + s.ordinal());
    16. printnb(s.compareTo(Shrubbery.CRAWLING) + " ");
    17. printnb(s.equals(Shrubbery.CRAWLING) + " ");
    18. print(s == Shrubbery.CRAWLING);
    19. print(s.getDeclaringClass());
    20. print(s.name());
    21. print("----------------------");
    22. }
    23. // Produce an enum value from a string name:
    24. for(String s : "HANGING CRAWLING GROUND".split(" ")) {
    25. Shrubbery shrub = Enum.valueOf(Shrubbery.class, s);
    26. print(shrub);
    27. }
    28.  
    29. // 編譯不過,在不同 enum 類型中進行比較
    30. Shrubbery.GROUND.compareTo(AnotherShrubbery.GROUND);
    31. }
    32. }

    為了驗證上面的推出的結果,我寫了下面手機類來進行測試。同類手機可以進行系統版本號的比較,不同類的手機系統版本號比較沒有意義。通過 E extends Handphone<E> 的泛型限定,我們就可以阻止編譯器在 Iphone 和 Android 手機之間進行系統版本號的比較。 www.it165.net

    01. //: generics/WeirdGenerics.java
    02. // 怪異的泛型
    03. package generics;
    04.  
    05. abstract class Handphone<E extends Handphone<E>> implements Comparable<E>{
    06. public abstract int osVersion();
    07. public int compareTo(E o){
    08. return osVersion() - o.osVersion();
    09. }
    10. }
    11.  
    12. class Iphone extends Handphone<Iphone>{
    13. private int version;
    14. public Iphone(int version){
    15. this.version = version;
    16. }
    17. public int osVersion(){
    18. return version;
    19. }
    20. }
    21.  
    22. class <a href="http://www.it165.net/pro/ydad/" target="_blank" class="keylink">Android</a> extends Handphone<Android>{
    23. private int version;
    24. public Android(int version){
    25. this.version = version;
    26. }
    27. public int osVersion(){
    28. return version;
    29. }
    30. }
    31.  
    32. public class WeirdGenerics{
    33. public static void main(String []args){
    34. Iphone i4 = new Iphone(4), i5 = new Iphone(5);
    35. Android a2 = new Android(2), a3 = new Android(3);
    36.  
    37. System.out.println(i5.compareTo(i4));
    38. System.out.println(a3.compareTo(a2));
    39. // 錯誤,兩種手機之間不能比較系統版本大小
    40. //System.out.println(i5.compareTo(a3));
    41. }
    42. }

     


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM