泛型可以減少強制類型的轉換,可規范集合的元素類型,還可以提高代碼的安全性和可讀性,正是因為有了這些優點,自從Java引入泛型之后,項目的編碼規則上便多了一條,優先使用泛型.
Java泛型(Generic)的引入加強了參數類型的安全性,減少了類型的轉換,它與C++中的模板templates比較類似.但是有一點,Java的反省在編譯期有效,在運行期被刪除,也就是說所有的泛型參數類型在編譯后都會被清除掉.
看如下代碼:
import java.util.List; public class Foo { //arrayMethod接受數組參數,並進行重載 public void arrayMethod(String[] strArray){} public void arrayMethod(Integer[] intArray){} //listMethod接收泛型List參數,並進行重載 public void listMethod(List<String> strList){} public void listMethod(List<Integer> intList){} }
編寫了4個方法,arrayMethod方法接收String數組和Integer數組,這是一個典型的重載,listMethod接收元素類型為String和Integer的List變量.
但是這段代碼不能通過編譯,不能通過通過編譯是在listMethod方法上.
提示:Erasure of method listMethod(List<String>) is the same as another method in type Foo && Erasure of method listMethod(List<Integer>) is the same as another method in type Foo
是說listMethod對應的這兩個方法在編譯時擦除類型后的方式是listMethod(List<E>),它與另外一個方法重復,通俗的說就是方法簽名重復,這就是Java泛型擦除引起問題:在編譯后所有的泛型類型都會做相應的轉化.
轉換規則如下:
1.List<String>,List<Integer>,List<T>泛型擦除后的類型為List.
2.List<String>[]擦除之后的類型是List[]
3.List<? extends E>,List<? super E>擦除之后對應類型是List<E>
4.List<T extends Serializable & Cloneable>擦除之后為List<Serializable>
Java編譯后的字節碼中已經沒有泛型的任何信息了,也就說一個泛型類和一個普通類在經過編譯后都指向了同一字節碼,比如Foo<T>類,經過編譯后將只有一份Foo.class類.
不管是Foo<String>還是Foo<Integer>引用的都是同一個字節碼,Java之所以這樣處理有兩方面原因:
1.避免JVM大換血.C++的泛型生命期延續到了運行期,而Java是在編譯器擦除掉的,如果JVM也把泛型類型延續到運行期,那么JVM就需要進行大量的重構工作了.
2.版本兼容,在 編譯期擦除可以更好的支持原生類型RawType,在Java1.5或1.6平台上,即使聲明一個List這樣的原生類型也是可以正常編譯通過的,只是會產生警告信息而已.
這樣就可以解釋如下問題了:
(1)泛型的class對象都是相同的.
每個類都有一個class屬性,泛型化不會改變class屬性的返回值.例如:
1 import java.util.ArrayList; 2 import java.util.List; 3 4 public class Client { 5 public static void main(String[] args) { 6 List<String> ls = new ArrayList<String>(); 7 List<Integer> li = new ArrayList<Integer>(); 8 System.out.println(li.getClass() == li.getClass()); 9 } 10 }
以上代碼會返回true,List<String>和List<Integer>擦除后的類型都是List,沒有任何的區別.
(2)泛型數組初始化時不能聲明泛型的類型
原因很簡單,可以聲明一個帶有泛型參數的數組,但是不能初始化該數組,因為執行了類型擦除操作,List<Object>[] 與List<String>就是一回事了,編譯器拒絕如此的聲明.
(3)instanceof不允許穿在泛型參數
原因 一樣,泛型類型的被擦除了.
1 import java.util.ArrayList; 2 import java.util.List; 3 4 public class Client { 5 public static void main(String[] args) { 6 //List<String>[] listArray = new List<String>[]; 7 /* 8 如上語句報錯 9 Multiple markers at this line 10 - Variable must provide either dimension expressions or an array initializer 11 - Cannot create a generic array of List<String> 12 */ 13 List<String>[] listArray2; //只聲明不初始化沒有問題. 14 //======================================分割線============ 15 16 List<String> list = new ArrayList<String>(); 17 System.out.println(list instanceof List);//沒有泛型就不會報錯, 18 //System.out.println(list instanceof List<String>);//有泛型就報錯. 19 /* 20 Cannot perform instanceof check against parameterized type List<String>. 21 Use the form List<?> instead since further generic type information will be erased at runtime 22 */ 23 24 List<String> list2 = new ArrayList<String>(); 25 List l = list2; 26 l.add(123); 27 } 28 }