聲明中具有一個(gè)或者多個(gè)類型參數(shù)的類或者接口锁施,就是泛型類或者接口陪踩。
沒有使用泛型的類型就是原生態(tài)類型。
每種泛型定義一組參數(shù)化的類型悉抵,結(jié)構(gòu)為:類或者接口的名稱<泛型類型>
如List<String>(讀作"字符串列表")是一個(gè)參數(shù)化的類型肩狂,表示元素類型為String的列表。
在jdk1.5之前沒有泛型的概念姥饰,在1.5發(fā)行版本中增加了泛型傻谁。在沒有泛型之前,從集合中讀取到的每一個(gè)對象都必須進(jìn)行轉(zhuǎn)換列粪。如果有人不小心插入了類型錯(cuò)誤的對象审磁,則在運(yùn)行時(shí)的轉(zhuǎn)換處理才會報(bào)錯(cuò)谈飒。有了泛型之后,可以告訴編譯器每個(gè)集合中接受哪些對象類型态蒂,編譯器自動(dòng)地為你的插入進(jìn)行轉(zhuǎn)換杭措,并在編譯時(shí)告知是否插入了類型錯(cuò)誤的對象。
使用泛型之前:
定義了一個(gè)集合钾恢,想要集合中包含的是stamp的實(shí)例
private final List stamps = new ArrayList();
在往集合中插入對象時(shí)手素,如果不小心將一個(gè)coin對象放進(jìn)了stamp集合中,編譯不會報(bào)錯(cuò)瘩蚪。
stamps.add(new Coin());
運(yùn)行到從stamp集合中獲取coin時(shí)才會報(bào)錯(cuò):
for(Object o : stamps){
Stamp s = (Stamp)o;
}
使用泛型:
private final List<Stamp> stamps = new ArrayList<Stamp>();
告訴了編譯器stamps集合應(yīng)該只包含Stamp實(shí)例泉懦,當(dāng)放入其他類型時(shí),會編譯報(bào)錯(cuò)疹瘦。
stamps.add(new Coin());
使用泛型還有一個(gè)好處就是不需要手動(dòng)做類型轉(zhuǎn)換崩哩,編譯器會替你隱式轉(zhuǎn)換。
for(Stamp s : stamps){
}
Iterator<Stamp> i = stamps.iterator();
while(i.hasNext()){
Stamp s = i.next();
}
當(dāng)然如果不提供類型參數(shù)言沐,使用原生態(tài)類型邓嘹,也仍然是合法的,但是不應(yīng)該這么做呢灶,這樣失掉了泛型在安全性和表述性方面的所有優(yōu)勢吴超。目前java保留了原生態(tài)類型是為了提供兼容性,因?yàn)樵诜盒统鰜砬耙呀?jīng)有大量沒有使用泛型的代碼鸯乃。為了這些代碼保持合法鲸阻,并且能夠與使用泛型的新代碼互用。因此在新代碼中不應(yīng)該使用原生態(tài)類型缨睡。
如果想插入任意對象鸟悴,可以使用List<Object>,那么它和原生態(tài)類型List有什么區(qū)別呢?
原生態(tài)類型逃避了泛型檢查奖年,而List<Object>則明確告訴編譯器细诸,它能夠持有任意類型的對象。
如List<String>可以傳遞給類型List的引用陋守,而不能傳遞給類型List<Object>的引用震贵。因此使用原生態(tài)類型會失掉類型安全性。
如原生態(tài)類型:運(yùn)行時(shí)會報(bào)類型轉(zhuǎn)換異常水评。
而使用參數(shù)化類型List<Object>: 在編譯時(shí)就會報(bào)錯(cuò)
如果不確定或不在乎集合元素的類型時(shí)猩系,可以使用無限制的通配符類型,以?來表示某種類型中燥,如Set<?>寇甸,表示某個(gè)類型的集合。
通配符類型是安全的,原生態(tài)類型則不安全拿霉,可以將任何元素插入到原生態(tài)類型集合中吟秩,因此很容易破壞集合類型的約束條件。但不能將任何元素(除了null)之外放到Collection<?>中绽淘,插入時(shí)會有編譯錯(cuò)誤涵防。
編譯錯(cuò)誤:
The method add(capture#5-of ?) in the type Set<capture#5-of ?> is not applicable for the arguments (int)
但無限制的通配符類型局限性很大,無法將任何元素放進(jìn)Collection<?>中收恢,而且根本無法猜測你會得到哪種類型的對象武学,解決這類問題祭往,可以使用泛型方法(27條)或者有限制的通配符類型(28)條來解決伦意。
不要在新代碼中使用原生態(tài)類型,這條規(guī)則有兩個(gè)小小的例外:
1.在類文字中必須使用原生態(tài)類型硼补。如:
List.class, String[].class, int.class都是合法的驮肉, 但是List<String>.class 和 List<?>.class則不合法。
2.在instanceof操作符關(guān)聯(lián)的類型使用原生態(tài)類型已骇。如
if (o instanceof Set) {
Set<?> m = (Set<?>)o;
}
由于泛型信息可以在運(yùn)行時(shí)被擦除离钝,因此在參數(shù)化類型而非無限制通配符類型上使用instanceof操作符是非法的。
使用無限制通配符類型代替原生態(tài)類型褪储,對instanceof操作符的行為不會產(chǎn)生任何影響卵渴,這種情況<?>就顯得多余。
因此instanceof操作符關(guān)聯(lián)的類型使用原生態(tài)類型鲤竹。
總結(jié):使用原生態(tài)類型會在運(yùn)行時(shí)導(dǎo)致異常浪读,因此不要在新代碼中使用。除非是類文字中或者instanceof中才使用原生態(tài)類型辛藻。
Set<Object>是參數(shù)化類型碘橘,表示可以包含任何對象類型的集合。Set<?>是通配符類型吱肌,標(biāo)示只包含某種未知對象類型的集合痘拆。Set則是原生態(tài)類型。前兩種是安全的氮墨,最后一種不安全纺蛆。