泛型的作用:告訴編譯器每個(gè)集合中可接受哪些對(duì)象類型获雕,編譯器自動(dòng)地為你的插入進(jìn)行轉(zhuǎn)化,并在編譯時(shí)告知是否插入錯(cuò)誤的對(duì)象收捣。這樣使程序既更加安全也更加清楚届案。
第二十三條、請(qǐng)不要在新代碼中使用原生態(tài)類型
-
聲明中具有一個(gè)或者多個(gè)類型參數(shù)的類或者接口罢艾,就是泛型類或者接口.
例:List接口只有單個(gè)類型參數(shù)E楣颠,表示列表的元素類型嫁乘。
List<E>
每種泛型定義一組參數(shù)化的類型,構(gòu)成的格式為:先是類或者接口名球碉,接著用尖括號(hào)<>把對(duì)應(yīng)于泛型形式類型參數(shù)的實(shí)際類型參數(shù)列表括起來蜓斧。如:List<String>
。 每個(gè)泛型都定義一個(gè)原生態(tài)類型(raw type)睁冬,即不帶任何實(shí)際類型參數(shù)的泛型名稱挎春。如:與List<E>對(duì)應(yīng)的原生類型是List。但如果使用原生態(tài)類型豆拨,就失掉了泛型在安全性和表述性方面的所有優(yōu)勢(shì)直奋。
-
安全的替代方法:無限制的通配符類型(unbounded wildcard type):
如果使用泛型,但不確定或者不關(guān)心實(shí)際的類型參數(shù)施禾,就可以使用一個(gè)問號(hào)代替脚线。
那么,Set<?>和Set的區(qū)別在哪弥搞?通配符類型是安全的邮绿,而原生態(tài)類型不安全。由于可以將任何元素放進(jìn)原生態(tài)類型的集合中攀例,因此很容易破壞該集合的類型約束條件船逮。 -
兩個(gè)例外情況:
在類文字中必須使用原生態(tài)類型,如:List.class粤铭,String[].class;
在instanceof中挖胃。 總結(jié):使用原生態(tài)類型會(huì)在運(yùn)行時(shí)導(dǎo)致異常,因此不要在新代碼中使用梆惯,原生態(tài)類型只是為了引入泛型之前的遺留代碼進(jìn)行兼容和互用而提供的酱鸭。Set<Object>是個(gè)參數(shù)化類型,表示可以包含任何對(duì)象類型的一個(gè)集合垛吗,Set<?>則是一個(gè)通配符類型凹髓,表示只能包含某種未知對(duì)象類型的一個(gè)集合,Set是個(gè)原生態(tài)類型职烧。前兩者是安全的扁誓,后面一種是不安全的防泵。
第二十四條蚀之、消除非受檢警告
泛型編程時(shí)會(huì)遇到許多編譯器的警告:非受檢強(qiáng)制轉(zhuǎn)化警告(unchecked cast warning)、非受檢方法調(diào)用警告捷泞、非受檢普通數(shù)組創(chuàng)建警告足删、以及非受檢轉(zhuǎn)換警告(unchecked conversion warnings)。有些警告可以根據(jù)編譯器來消除锁右,但是有些警告難以消除失受,同時(shí)可以證明引起警告的代碼是類型安全的讶泰,可以用一個(gè)
@SuppressWarnings("unchecked")
來禁止這條警告。@SuppressWarnings("unchecked")
可以在任何粒度的級(jí)別中拂到,應(yīng)該始終在盡可能小的范圍內(nèi)使用SuppressWarnings注解痪署。它通常是個(gè)變量聲明,或是非常簡(jiǎn)單的方法或者構(gòu)造器兄旬。
第二十五條狼犯、列表優(yōu)先于數(shù)組
-
數(shù)組與泛型相比的不同點(diǎn):
-
數(shù)組是協(xié)變的(covariant),即如果Sub為Super的子類型领铐,即Sub[]為Super[]的子類型悯森。而泛型是不可變的。這么看來绪撵,數(shù)組是有缺陷的瓢姻。
//編譯時(shí)是合法的 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");
數(shù)組是具體化的(reified),因此數(shù)組會(huì)在運(yùn)行時(shí)才知道檢查它們的元素類型約束;相比之下音诈,泛型則是通過擦除(erasure)來實(shí)現(xiàn)的幻碱,因此泛型只在編譯時(shí)強(qiáng)化它們的類型信息,并在運(yùn)行時(shí)丟棄它們的元素信息细溅。
由于上面的兩個(gè)區(qū)別收班,數(shù)組和泛型不能很好地混合使用。
-
從技術(shù)的角度說:像
E
谒兄、List<E>
和List<String>
這樣的類型應(yīng)稱作不可具體化的類型(直觀上說是指其運(yùn)行時(shí)表示法包含的信息比它編譯時(shí)表示包含法的信息更少的類型摔桦。)唯一可具體化的參數(shù)化類型是無限制的通配符類型,如List<?
>和Map<?,?>
雖然不常用承疲,但創(chuàng)建無限制通配符類型的數(shù)組是合法的邻耕。總結(jié):數(shù)組和泛型有著非常不同的類型規(guī)則。數(shù)組是協(xié)變且可以具體化燕鸽。泛型是不可變的且可以被擦除兄世,一般數(shù)組和泛型不能很好地混合使用,如果編譯錯(cuò)誤得到警告啊研,第一反應(yīng)時(shí)用列表代替數(shù)組御滩。
第二十六條、優(yōu)先考慮泛型
第二十七條党远、優(yōu)先考慮泛型方法
第二十八條削解、利用有限制通配符來提升API的靈活性
-
Java提供了一種特殊的參數(shù)化類型,稱作有限制的通配符類型:
<? extends E >
E的某個(gè)子類型沟娱,確定了子類型之后氛驮,每個(gè)類型都是自己的子類型。
<? super E>
E的某個(gè)超類济似,每個(gè)類型都是自己的超類矫废。 為了獲得最大限度的靈活性盏缤,要在表示生產(chǎn)者或者消費(fèi)者的輸入?yún)?shù)上使用通配符類型,如果某個(gè)輸入?yún)?shù)既是生產(chǎn)者又是消費(fèi)者蓖扑,那么通配符類型就沒有用了唉铜,因?yàn)槟阈枰氖菄?yán)格的類型匹配。
-
助記符:PECS: producer-extends,consumer-super:
如果參數(shù)化類型表示一個(gè)T生產(chǎn)者律杠,就使用
<? extends T>
打毛,如果表示一個(gè)T消費(fèi)者,則使用<俩功?super T>
幻枉,所有的comparable和comparator都是消費(fèi)者。 不要用通配符類型作為返回類型诡蜓! 通配符類型對(duì)于類的用戶來說應(yīng)是無形的熬甫。
第二十九條、優(yōu)先考慮類型安全的異構(gòu)容器
泛型最常用于集合(Set或者M(jìn)ap)以及單元素的容器蔓罚。在這些用法中椿肩,它都充當(dāng)被參數(shù)化了的容器。這樣就限制了每個(gè)容器只能有固定數(shù)目的類型參數(shù)豺谈,一個(gè)Set只有一個(gè)類型參數(shù)郑象,表示它的元素類型,一個(gè)Map有兩個(gè)類型參數(shù)茬末,表示它的鍵和值得類型厂榛。
可以通過將類型參數(shù)放在鍵上而不是容器上來避開這種限制,對(duì)于這種類型安全的異構(gòu)容器丽惭,可以用Class對(duì)象作為鍵击奶。