java 泛型是java SE 1.5的新特性,泛型的本質是參數化類型,也就是說所操作的數據類型被指定爲一個參數。這種參數類型可以用在類、接口和方法的創建中,分別稱爲泛型類、泛型接口、泛型方法。
泛型(Generic type 或者generics)是對Java語言的類型系統的一種擴展,以支持創建可以按類型進行參數化的類。可以把類型參數看作是使用參數化類型時指定的類型佔位符,就像方法的形式參數是運行時傳遞的值得佔位符一樣。
泛型爲提高大型程序的類型安全和可維護性帶來了很大的潛力。
可以在集合框架(Collection framework)中看到泛型的動機。例如,Map 類允許您向一個 Map 添加任意類的對象,即使最常見的情況是在給定映射(map)中保存某個特定類型(比如 String)的對象。
因爲 Map.get() 被定義爲返回 Object,所以一般必須將 Map.get() 的結果強制類型轉換爲期望的類型,如下面的代碼所示:
Map m = new HashMap();
m.put("key", "blarg");
String s = (String) m.get("key");
要讓程序通過編譯,必須將 get() 的結果強制類型轉換爲 String,並且希望結果真的是一個 String。但是有可能某人已經在該映射中保存了不是 String 的東西,這樣的話,上面的代碼將會拋出 ClassCastException。
理想情況下,您可能會得出這樣一個觀點,即 m 是一個 Map,它將 String 鍵映射到 String 值。這可以讓您消除代碼中的強制類型轉換,同時獲得一個附加的類型檢查層,該檢查層可以防止有人將錯誤類型的鍵或值保存在集合中。這就是泛型所做的工作。
泛型的好處
Java 語言中引入泛型是一個較大的功能增強。不僅語言、類型系統和編譯器有了較大的變化,以支持泛型,而且類庫也進行了大翻修,所以許多重要的類,比如集合框架,都已經成爲泛型化的了。
這帶來了很多好處:
1,類型安全。 泛型的主要目標是提高 Java 程序的類型安全。通過知道使用泛型定義的變量的類型限制,編譯器可以在一個高得多的程度上驗證類型假設。沒有泛型,這些假設就只存在於程序員的頭腦中(或者如果幸運的話,還存在於代碼註釋中)。
2,消除強制類型轉換。 泛型的一個附帶好處是,消除源代碼中的許多強制類型轉換。這使得代碼更加可讀,並且減少了出錯機會。
3,潛在的性能收益。 泛型爲較大的優化帶來可能。在泛型的初始實現中,編譯器將強制類型轉換(沒有泛型的話,程序員會指定這些強制類型轉換)插入生成的字節碼中。但是更多類型信息可用於編譯器這一事實,爲未來版本的 JVM 的優化帶來可能。由於泛型的實現方式,支持泛型(幾乎)不需要 JVM 或類文件更改。所有工作都在編譯器中完成,編譯器生成類似於沒有泛型(和強制類型轉換)時所寫的代碼,只是更能確保類型安全而已。
Java語言引入泛型的好處是安全簡單。泛型的好處是在編譯的時候檢查類型安全,並且所有的強制轉換都是自動和隱式的,提高代碼的重用率。
泛型在使用中還有一些規則和限制:
1、泛型的類型參數只能是類類型(包括自定義類),不能是簡單類型。
2、同一種泛型可以對應多個版本(因爲參數類型是不確定的),不同版本的泛型類實例是不兼容的。
3、泛型的類型參數可以有多個。
4、泛型的參數類型可以使用extends語句,例如<T extends superclass>。習慣上成爲“有界類型”。
5、泛型的參數類型還可以是通配符類型。例如Class<?> classType = Class.forName(Java.lang.String);
泛型還有接口、方法等等,內容很多,需要花費一番功夫才能理解掌握並熟練應用。
public class GenericHolder<T> { //泛型類,參數化類型,也體現了多態特徵。
private T contenT;
public T getContenT() {
return contenT;
}
public void setContenT(T contenT) {
this.contenT = contenT;
}
public static void main(String[] args) {
GenericHolder<String> sHolder=new GenericHolder<String>();//在編譯時就能夠檢查類型安全,T在運行時被String替換
sHolder.setContenT("liqingan");
String name=sHolder.getContenT();
System.out.println(name);
System.out.println(sHolder.getClass()); //getClass()是用來獲取類本身的
GenericHolder<Integer> iHolder=new GenericHolder<Integer>();
iHolder.setContenT(25);
Integer age=iHolder.getContenT();
System.out.println(age);
System.out.println(iHolder.getClass());
}
}
類型參數
在定義泛型類或聲明泛型類的變量時,使用尖括號來指定形式類型參數。形式類型參數與實際類型參數之間的關係類似於形式方法參數與實際方法參數之間的關係,只是類型參數表示類型,而不是表示值。
泛型類中的類型參數幾乎可以用於任何可以使用類名的地方(變量、屬性、參數、返回值......)。
類型參數也允許有多個同時存在,多個類型參數之間用“,”進行分隔。
public class GenericHolder<K,V> { //類型參數可以有多個,之間用,分隔
private K key;
private V value;
public void put(K key,V value){
this.key=key;
this.value=value;
}
public V get(K key){
if (this.key.equals(key)) {
return value;
}
return null;
}
public static void main(String[] args) {
}
}
類型參數命名
推薦的命名約定是使用大寫的單個字母名稱作爲類型參數。
對於常見的泛型模式,推薦的名稱是:
T---泛型。
K---鍵,比如映射的鍵。
V---值,比如List或Set的內容,或者Map中的值。
E---異常類。