第五章、泛型

泛型的作用:告訴編譯器每個集合中可接受哪些對象類型,編譯器自動地為你的插入進行轉化,并在編譯時告知是否插入錯誤的對象。這樣使程序既更加安全也更加清楚。

第二十三條、請不要在新代碼中使用原生態類型

  1. 聲明中具有一個或者多個類型參數的類或者接口,就是泛型類或者接口.

    例:List接口只有單個類型參數E,表示列表的元素類型。List<E>
    每種泛型定義一組參數化的類型,構成的格式為:先是類或者接口名,接著用尖括號<>把對應于泛型形式類型參數的實際類型參數列表括起來。如:List<String>。

  2. 每個泛型都定義一個原生態類型(raw type),即不帶任何實際類型參數的泛型名稱。如:與List<E>對應的原生類型是List。但如果使用原生態類型,就失掉了泛型在安全性和表述性方面的所有優勢。

  3. 安全的替代方法:無限制的通配符類型(unbounded wildcard type):

    如果使用泛型,但不確定或者不關心實際的類型參數,就可以使用一個問號代替。
    那么,Set<?>和Set的區別在哪?通配符類型是安全的,而原生態類型不安全。由于可以將任何元素放進原生態類型的集合中,因此很容易破壞該集合的類型約束條件。

  4. 兩個例外情況:

    在類文字中必須使用原生態類型,如:List.class,String[].class;
    在instanceof中。

  5. 總結:使用原生態類型會在運行時導致異常,因此不要在新代碼中使用,原生態類型只是為了引入泛型之前的遺留代碼進行兼容和互用而提供的。Set<Object>是個參數化類型,表示可以包含任何對象類型的一個集合,Set<?>則是一個通配符類型,表示只能包含某種未知對象類型的一個集合,Set是個原生態類型。前兩者是安全的,后面一種是不安全的。


第二十四條、消除非受檢警告

  1. 泛型編程時會遇到許多編譯器的警告:非受檢強制轉化警告(unchecked cast warning)、非受檢方法調用警告、非受檢普通數組創建警告、以及非受檢轉換警告(unchecked conversion warnings)。有些警告可以根據編譯器來消除,但是有些警告難以消除,同時可以證明引起警告的代碼是類型安全的,可以用一個@SuppressWarnings("unchecked")來禁止這條警告。

  2. @SuppressWarnings("unchecked")可以在任何粒度的級別中,應該始終在盡可能小的范圍內使用SuppressWarnings注解。它通常是個變量聲明,或是非常簡單的方法或者構造器。


第二十五條、列表優先于數組

  1. 數組與泛型相比的不同點:

    • 數組是協變的(covariant),即如果Sub為Super的子類型,即Sub[]為Super[]的子類型。而泛型是不可變的。這么看來,數組是有缺陷的。

            //編譯時是合法的
            Object[] objectArray = new Long[1];
            objectArray[0] = "I don't fit in";
            //Won't Compile
            List<Object> ol = new ArrayList<Long>();
            ol.add("I don't fit in");  
      
    • 數組是具體化的(reified),因此數組會在運行時才知道檢查它們的元素類型約束;相比之下,泛型則是通過擦除(erasure)來實現的,因此泛型只在編譯時強化它們的類型信息,并在運行時丟棄它們的元素信息。

    • 由于上面的兩個區別,數組和泛型不能很好地混合使用。

  2. 從技術的角度說:像E、List<E>List<String>這樣的類型應稱作不可具體化的類型(直觀上說是指其運行時表示法包含的信息比它編譯時表示包含法的信息更少的類型。)唯一可具體化的參數化類型是無限制的通配符類型,如List<?>和Map<?,?>雖然不常用,但創建無限制通配符類型的數組是合法的。

  3. 總結:數組和泛型有著非常不同的類型規則。數組是協變且可以具體化。泛型是不可變的且可以被擦除,一般數組和泛型不能很好地混合使用,如果編譯錯誤得到警告,第一反應時用列表代替數組。


第二十六條、優先考慮泛型

第二十七條、優先考慮泛型方法


第二十八條、利用有限制通配符來提升API的靈活性

  1. Java提供了一種特殊的參數化類型,稱作有限制的通配符類型:

    <? extends E >E的某個子類型,確定了子類型之后,每個類型都是自己的子類型。
    <? super E> E的某個超類,每個類型都是自己的超類。

  2. 為了獲得最大限度的靈活性,要在表示生產者或者消費者的輸入參數上使用通配符類型,如果某個輸入參數既是生產者又是消費者,那么通配符類型就沒有用了,因為你需要的是嚴格的類型匹配。

  3. 助記符:PECS: producer-extends,consumer-super

    如果參數化類型表示一個T生產者,就使用<? extends T>,如果表示一個T消費者,則使用<?super T>,所有的comparable和comparator都是消費者。

  4. 不要用通配符類型作為返回類型! 通配符類型對于類的用戶來說應是無形的。


第二十九條、優先考慮類型安全的異構容器

  1. 泛型最常用于集合(Set或者Map)以及單元素的容器。在這些用法中,它都充當被參數化了的容器。這樣就限制了每個容器只能有固定數目的類型參數,一個Set只有一個類型參數,表示它的元素類型,一個Map有兩個類型參數,表示它的鍵和值得類型。

  2. 可以通過將類型參數放在鍵上而不是容器上來避開這種限制,對于這種類型安全的異構容器,可以用Class對象作為鍵。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容