Technorati 標記: java,泛型,generic
java泛型應用是java核心基礎之一,從java 5開始引進泛型。如果你曾經使用過java Collection,那你已經算是接觸過泛型了。在java Collection裡使用泛型是一件很簡單的事情,可泛型還具有很多你意想不到的作用。在深入了解泛型之前,首先來了解一下泛型的一些基本概念與原理。
一、java 泛型引入
java泛型的應用可以提高的代碼的復用性,同時泛型提供了類型檢查,減少了數據的類型轉換,同時保證了類型安全。下面看一下,泛型如何保證了類型安全:
List list = new ArrayList();
list.add("abc");
list.add(new Integer(1)); //可以通過編譯
for (Object object : list) {
System.out.println((String)object);//拋出ClassCastException異常
}
上面的代碼會在運行時拋出ClassCastException,因為它嘗試將一個Integer轉換為String。接著,來看一下從java5開始,Collection的用法:
List<String> list = new ArrayList<>();
list.add("abc");
//list.add(new Integer(1)); //編譯錯誤
for (String string : list) {
System.out.println(string);//無需任何強制類型轉換
}
注意到,List的創建增加了類型參數String,因此只能向list添加String類型對象,添加其他對象會拋出編譯異常;同樣可以注意到,foreach循環不需要再添加任何強制類型轉換,也就移除了運行時的ClassCastException異常。
二、泛型的類與接口
既然是學泛型,自然就要知道如何去使用泛型定義自己的類和接口。同時為了加深理解泛型的作用,先引進一個原始的類:
public class Gen {
private Object obj;
public Object getObj() {
return obj;
}
public void setObj(Object obj) {
this.obj = obj;
}
public static void main(String[] args) {
Gen gen = new Gen();
gen.setObj("abc");
String str = (String) gen.getObj();//類型轉換,可能會引起運行時ClassCastException
}
}
原始類的定義,容易引發ClassCastException,和第一大點談到的類似。現在來看一下泛型類來重新定義Gen — 使用<>指定泛型參數,如下:
public class Gen<T> {
T obj;
public T getObj() {
return obj;
}
public void setObj(T obj) {
this.obj = obj;
}
public static void main(String[] args) {
Gen<String> gen = new Gen<>();
gen.setObj("abc");
// gen.setObj(10); //無法通過編譯
String str = gen.getObj(); //無需類型轉換
//-----------------------------
Gen gen2 = new Gen();//raw type原始類型
gen2.setObj("abc");
gen2.setObj(10); //可以通過編譯,自動裝箱將10轉化為Integer對象
Integer num = (Integer) gen2.getObj();//使用了強制類型轉換
}
} 細心的你會發現在main()方法裡是使用泛型類型Gen<String>,便不再需要強制類型轉換,也就移除了運行時的ClassCastException。同時為了區別,在此也定義了一個沒有使用泛型類型的gen2,這時,編譯器會彈出一個警告“Gen is a raw type,References to generic type Gen<T> should be parameterized”。當我們不提供泛型類型時,會默認使用Object會代替,也是因此這樣,gen2可以設置String和Integer類型,不過,我們應盡量去避免這種這種情況的出現,如此,便又需要用到強制類型轉換,也伴隨著運行時的ClassCastException異常。
tips:可以使用@SuppressWarnings("rawtypes")來抑制編譯器彈出警告。
接口的泛型應用和類的泛型應用很類似,如下:
public interface List <E> {
void add(E x);
Iterator<E> iterator();
}
public interface Iterator<E> {
E next();
boolean hasNext();
}
類似的,可以將此應用到自定義的接口與類當中。另外再提一下的是,可以使用多個泛型參數來定義接口與類,比如Map<K,V>;同時,泛型類型也可以作為一個參數來用,如下:new HashMap<String, List<String>>()。
更多詳情見請繼續閱讀下一頁的精彩內容: http://www.linuxidc.com/Linux/2013-10/90922p2.htm