Effective Java读书笔记七:泛型(部分章节需要重读)
第23條:請(qǐng)不要在新代碼中使用原生態(tài)類(lèi)型
從java1.5發(fā)行版本開(kāi)始,Java就提供了一種安全的替代方法,稱(chēng)作無(wú)限制的通配符類(lèi)型,如果要使用范型,但是確定或者不關(guān)心實(shí)際的參數(shù)類(lèi)型,就可以用一個(gè)問(wèn)號(hào)代替。例如范型Set<?>的無(wú)限制通配符類(lèi)型為Set<?>。這是最普通的參數(shù)化Set類(lèi)型,可以持有任何集合。
關(guān)于Set<?>的兩個(gè)事實(shí):?
1、因?yàn)椤?#xff1f;”標(biāo)記可以代表任何類(lèi)型,Set<?>可以持有任何類(lèi)型的元素?
2、由于不知道“?”代表的類(lèi)型,所有我們不能把任何元素放到Set<?>集合中
由于可以將任何元素放進(jìn)使用原生態(tài)類(lèi)型的集合中,因此很容易破壞該集合的類(lèi)型約束條件;但不能將任何元素(除了null之外)放到Collection<?>中。
“不要在新代碼中使用原生態(tài)類(lèi)型”,這條規(guī)則有兩個(gè)例外,這是因?yàn)椤?span style="color:Crimson">泛型信息在運(yùn)行時(shí)就會(huì)被擦除”。
在獲取類(lèi)信息中必須使用原生態(tài)類(lèi)型(數(shù)組類(lèi)型和基本類(lèi)型也算原生態(tài)類(lèi)型),規(guī)范不允許使用參數(shù)化類(lèi)型。換句話(huà)說(shuō):List.class,String[].class和int.class都是合法,但是List<String>.class和List<?>.class都是不合法的。
這條規(guī)則的第二個(gè)例外與instanceof操作符有關(guān),由于泛型信息在運(yùn)行時(shí)已被擦除,因此在參數(shù)化類(lèi)型而不是無(wú)限制通配符類(lèi)型(如List<?>)上使用instanceof操作符是非法的,用無(wú)限制通配符類(lèi)型代替原生態(tài)類(lèi)型,對(duì)instanceof操作的行為不產(chǎn)生任何影響。在這種情況下,尖括號(hào)<>和問(wèn)號(hào)?就顯得多余了。
下面是利用泛型來(lái)使用instanceof操作符的首先方法:
if(o instanceof set){Set<?> m = (Set<?>)o;// ... }- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
注意,一旦確定這個(gè)o是個(gè)Set,就必須將它轉(zhuǎn)換成通配類(lèi)型Set<?>,則不是轉(zhuǎn)換成原生態(tài)類(lèi)型Set,否則Set會(huì)引起編譯時(shí)警告。
總之,使用原生態(tài)類(lèi)型會(huì)在運(yùn)行時(shí)導(dǎo)致異常,因此不要在新代碼中使用。原生態(tài)類(lèi)型只為了與引入泛型之前的遺留代碼進(jìn)行兼容和互用而提供的。另外Set<Object>是個(gè)參數(shù)化類(lèi)型,表示可以包括任何對(duì)象類(lèi)型的一個(gè)集合;Set<?>則是一個(gè)通配符類(lèi)型,表示只能包含某種未知對(duì)象類(lèi)型的一個(gè)集合;Set則是個(gè)原生態(tài)類(lèi)型,它脫離了泛型系統(tǒng)。前兩者是安全的,最后一種不安全。
術(shù)語(yǔ)介紹:?
原生態(tài)類(lèi)型:List?
參數(shù)化的類(lèi)型:List<String>?
泛型:List<E>?
有限制類(lèi)型參數(shù):List<E extends Number>?
形式類(lèi)型參數(shù):E?
無(wú)限制通配符類(lèi)型:List<?>?
有限制通配符類(lèi)型:List<? extends Number>?
遞歸類(lèi)型限制:List <T extends Comparable>?
泛型方法: static<E> List<E> asList(E[] a)
第24條:消除非受檢警告
用泛型編程時(shí),會(huì)遇到許多編譯器警告:非受檢強(qiáng)制轉(zhuǎn)換警告、非受檢方法調(diào)用警告、非受檢普通數(shù)組創(chuàng)建警告,以及非受檢轉(zhuǎn)換警告。
要盡可能地消除每一個(gè)非受檢警告。如果消除了所有警告,就可以確保代碼是類(lèi)型安全的。
如果無(wú)法消除警告,同時(shí)可以證明引起警告的代碼是類(lèi)型安全的,只有在這種情況下才可以用一個(gè)@SuppressWarnings(“unchecked”)注解來(lái)禁止這條警告。
SuppressWarnings注解可以用在任何粒度的級(jí)別中,從單獨(dú)的局部變量到整個(gè)類(lèi)都可以。應(yīng)該始終在盡可能小的范圍中使用SuppressWarnings注解。它通常是個(gè)變量聲明,或者是非常簡(jiǎn)短的方法或者構(gòu)造器。永遠(yuǎn)不要在整個(gè)類(lèi)上使用SuppressWarnings,這么做可能會(huì)掩蓋了重要的警告。
總而言之,非受檢警告很重要,不要忽略它們。每一條警告都表示可能在運(yùn)行時(shí)拋出ClassCastException異常。要盡最大的努力消除這些警告。如果無(wú)法消掉同時(shí)確實(shí)是類(lèi)型安全的,就可以在盡可能小的范圍中,用@SuppressWarnings(“unchecked”)注解來(lái)禁止這條警告。要用注釋把禁止該警告的原因記錄下來(lái)。
第25條:列表優(yōu)先于數(shù)組
1、數(shù)組是協(xié)變的(convariant),如果Sub是Super的子類(lèi)型,那么數(shù)組類(lèi)型Sub[]就是Super[]的子類(lèi)型。?
泛型確實(shí)不可變的,List<Sub>不是List<Super>的子類(lèi)型。
2、數(shù)組是具體化的(reified),因此數(shù)組在運(yùn)行時(shí)才知道并檢查它們的元素類(lèi)型約束。?
泛型則是通過(guò)擦除(erasure)來(lái)實(shí)現(xiàn),因此泛型只在編譯時(shí)強(qiáng)化它們的類(lèi)型信息,并在運(yùn)行時(shí)丟棄(或者擦除)它們的元素類(lèi)型約束。擦除就是使泛型可以與沒(méi)有使用泛型的代碼隨意進(jìn)行互用(見(jiàn)第23條)。?
下面代碼片段是合法的:
- 1
- 2
- 1
- 2
但是下面的代碼則是不合法的:
List<Object> ol = new ArrayList<Long>();//Incompatible types 不兼容類(lèi)型 ol.add("I don't fit in");- 1
- 2
- 1
- 2
這其中無(wú)論是那種方法,都不能將String類(lèi)型放進(jìn)Long容器中,但是利用數(shù)組,你會(huì)在運(yùn)行時(shí)拋出所犯的錯(cuò)誤,利用List列表,則是在編譯時(shí)就能看到發(fā)生的錯(cuò)誤,我們當(dāng)然希望在編譯時(shí)發(fā)現(xiàn)錯(cuò)誤了。
由于上述這些根本的區(qū)別,因此數(shù)組和泛型不能很好的混合使用。例如,創(chuàng)建泛型,參數(shù)化類(lèi)型或者類(lèi)型參數(shù)的數(shù)組是非法的。這些數(shù)組創(chuàng)建表達(dá)式?jīng)]有一個(gè)是合法的:new List<E>、new List<String>[]和new E[]。這些在編譯的時(shí)都會(huì)導(dǎo)致一個(gè)generic array creation(泛型創(chuàng)建數(shù)組)錯(cuò)誤。
第26條:優(yōu)先考慮泛型(需要重新讀)
使用泛型比使用需要在客戶(hù)端代碼中進(jìn)行轉(zhuǎn)換的類(lèi)型來(lái)的更加安全,也更加容易。在設(shè)計(jì)新類(lèi)型的時(shí)候,要確保它們不需要這種轉(zhuǎn)換就可以使用。這通常意味著要把類(lèi)做成是泛型的。
第27條:優(yōu)先考慮泛型方法(需要重新讀)
泛型方法就想泛型對(duì)象一樣,使用起來(lái)比要求客戶(hù)端轉(zhuǎn)換輸入?yún)?shù)并返回值的方法來(lái)得更加安全,也更加容易。就像類(lèi)型一樣,你應(yīng)該確保新方法可以不用轉(zhuǎn)換就能使用,這通常意味著要將它們泛型化。
第28條:利用有限制通配符來(lái)提升API的靈活性(需要重新讀)
為了獲得最大限度的靈活性,要在表示生產(chǎn)者和消費(fèi)者的輸入?yún)?shù)上使用通配符類(lèi)型。如果某個(gè)輸入?yún)?shù)即是生產(chǎn)者,又是消費(fèi)都,那么通配符類(lèi)型對(duì)你就沒(méi)有什么好處了,因?yàn)槟阈枰獓?yán)格的類(lèi)型匹配,這是不用任何通配符而得到的。
下面的助記符便于讓你記住要使用哪種通配符類(lèi)型:
PECS 表示:producer-extends, consumer-super?
換句話(huà)說(shuō),如果參數(shù)化類(lèi)型表示一個(gè)T生產(chǎn)者,就使用<? extends T>;如果它表示一個(gè)T消費(fèi)者,就使用<? super T>。
PECS這個(gè)助記符突出了使用通配符的基本原則。Naftalin和Wadler稱(chēng)之為Get and Put Principle
第29條:優(yōu)先考慮類(lèi)型安全的異構(gòu)容器(需要重新讀)
集合API說(shuō)明了泛型的一般用法,限制你每個(gè)容器只能有固定數(shù)目的類(lèi)型參數(shù)。你可以通過(guò)將類(lèi)型參數(shù)放在鍵上而不是容器上這一限制。對(duì)于這種類(lèi)型安全的異構(gòu)容器,可以用Class對(duì)象作為鍵。以這種方式使用的Class對(duì)象稱(chēng)作類(lèi)型令牌。
《Effective Java中文版 第2版》PDF版下載:?
http://download.csdn.net/detail/xunzaosiyecao/9745699
作者:jiankunking 出處:http://blog.csdn.net/jiankunking
from:?http://blog.csdn.net/jiankunking/article/details/54881166
總結(jié)
以上是生活随笔為你收集整理的Effective Java读书笔记七:泛型(部分章节需要重读)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Effective Java读书笔记六:
- 下一篇: Http Server : 一个差生的逆