天天看點

Java基礎之泛型

一、泛型的引入

泛型是Java SE 1.5的新特性,泛型的本質是參數化類型,也就是說所操作的資料類型被指定為一個參數。這種參數類型可以用在類、接口和方法的建立中,分别稱為泛型類、泛型接口、泛型方法。 Java語言引入泛型的好處是安全簡單。

在Java SE 1.5之前,沒有泛型的情況的下,通過對類型Object的引用來實作參數的“任意化”,“任意化”帶來的缺點是要做顯式的強制類型轉換,而這種轉換是要求開發者對實際參數類型可以預知的情況下進行的。對于強制類型轉換錯誤的情況,編譯器可能不提示錯誤,在運作的時候才出現異常,這是一個安全隐患。

泛型的好處是在編譯的時候檢查類型安全,并且所有的強制轉換都是自動和隐式的,以提高代碼的重用率。

二、泛型的應用

1、泛型類型

用于類的定義中,被稱為泛型類。通過泛型可以完成對一組類的操作對外開放相同的接口。最典型的就是各種容器類,如:List、Set、Map。泛型的類型參數隻能是類類型,不能是簡單類型。不能對确切的泛型類型使用instanceof操作。如下面的操作是非法的,編譯時會出錯。

2、泛型接口

與泛型類的定義及使用基本相同。泛型接口常被用在各種類的生産器中。

3、泛型方法

無論何時,如果你能做到,你就該盡量使用泛型方法。也就是說,如果使用泛型方法将整個類泛型化,那麼就應該使用泛型方法。另外對于一個static的方法而已,無法通路泛型類型的參數。是以如果static方法要使用泛型能力,就必須使其成為泛型方法。 

靜态方法有一種情況需要注意一下,那就是在類中的靜态方法使用泛型:靜态方法無法通路類上定義的泛型;如果靜态方法操作的引用資料類型不确定的時候,必須要将泛型定義在方法上。

泛型類,是在執行個體化類的時候指明泛型的具體類型;泛型方法,是在調用方法的時候指明泛型的具體類型

如果靜态方法要使用泛型的話,必須将靜态方法也定義成泛型方法 。

三、泛型通配符

前面提到,Java引入泛型是為了編譯時類型檢查,在聲明時确定具體的類型,在使用是就不用再進行強者類型轉換,簡單且安全。但Java泛型隻在編譯時有效,在運作時泛型類型已被擦除。為了減少運作時類型錯誤,Java規定泛型類不能傳遞繼承關系,即若A是B父類,List<A>也不是List<B>父類,即List<Object> list = new ArrayList<String>();無法編譯通過。如果确實要引入父類,實作類似繼承操作怎麼辦?于是引入類型通配符“?",代表未知類型,它是類型實參,“?”就是一個通配符,它隻能在“<>”中使用。通配符隻能出現在引用的定義中,而不能出現在建立對象中。例如:new ArrayList<?>(),這是不可以的。ArrayList<?> list = null,這是可以的。

如List<?> list = new ArrayList<String>();List<?>可以看作List<String>等所有類的父類(注意List<?>和List<Object>不同,前者是某種未知類型,可看作List<String>的父類,但List<Object>是确定類型,不能當做List<String>父類),但由于list屬于某種未知的類型,是以無法将其當做List<String>處理(同樣,Java中父類不能當做子類處理,隻有子類能被看作父類使用),list.add("hello")非法。

?表示無限界通配符,可以限定上或下邊界通配符(不能同時限定上下邊界),如:

List<? extends ParentClass&Interface1>限定其父類必須為類ParentClass,且實作接口Interface1,List<?>其實相當于List<? extends Object>,由于類型不确定性無法向List<? extends ParentClass&Interface1>中添加除null以外的對象。

List<? super Number>限定其下邊界必須為Number或為Number的父類,不過List中元素類型的繼承關系和List<?>繼承關系,此時可以向list中添加Number的子類對象,

 四、注意事項

在java中是”不能建立一個确切的泛型類型的數組”

由于JVM泛型的擦除機制,在運作時JVM是不知道泛型資訊的,是以可以給oa[1]賦上一個ArrayList而不會出現異常,但是在取出資料的時候卻要做一次類型轉換,是以就會出現ClassCastException,如果可以進行泛型數組的聲明,上面說的這種情況在編譯期将不會出現任何的警告和錯誤,隻有在運作時才會出錯。而對泛型數組的聲明進行限制,對于這樣的情況,可以在編譯期提示代碼有類型安全問題,比沒有任何提示要強很多。

繼續閱讀