爲什麼要用泛型呢?JDK5以前,對象保存到集合中就會失去其特性,取出時通常要程序員手工進行類型的強制轉換,這樣不可避免就會引發程序的一些安全性問題。
比如:
泛型的作用:
JDK5中的泛形允許程序員在編寫集合代碼時,就限制集合的處理類型,從而把原來程序運行時可能發生問題,轉變爲編譯時的問題,以此提高程序的可讀性和穩定性(尤其在大型程序中更爲突出)。
注意:泛型是提供給javac編譯器使用的,它用於限定集合的輸入類型,讓編譯器在源代碼級別上,即擋住向集合中插入非法數據。但編譯器編譯完帶有泛形的java程序後,生成的class文件中將不再帶有泛形信息,以此使程序運行效率不受到影響,這個過程稱之爲“擦除”。
泛形的基本術語,以ArrayList<E>爲例:<>念做typeof
ArrayList<E>中的E稱爲類型參數變量
ArrayList<Integer>中的Integer稱爲實際類型參數
整個稱爲ArrayList<E>泛型類型
整個ArrayList<Integer>稱爲參數化的類型ParameterizedType
泛型的應用:
使用迭代器迭代泛形集合中的元素:
增強for循環迭代泛形集合中的元素:
HashMap中的元素:
import java.util.*;
import java.util.Map.Entry;
public class MapTest{
public static void main(String [] args){
Map<Integer,String> map=new HashMap<Integer,String>();
map.put(1,"x");
map.put(2,"a");
map.put(3,"z");
map.put(4,"s");//添加數據
/**
*兩種遍歷Map集合中數據的方法
*/
//通過set來遍歷
Set<Integer> set=map.keySet();//返回鍵值的set視圖
Iterator<Integer> it=set.iterator();//在這裏,如果不加上泛型約束的話,就無法找到需要的類型
while(it.hasNext()){
Integer e=it.next();
String v=map.get(e);
System.out.println(v);
}
//通過Entry來遍歷
Set<Entry<Integer,String>> entrys=map.entrySet();//返回映射項的set視圖
Iterator<Entry<Integer,String>> its=entrys.iterator();
while(its.hasNext()){
Entry<Integer,String> entry=its.next();
System.out.println(entry.getKey()+"->"+entry.getValue());
}
}
}
¨使用泛形時的幾個常見問題:
使用泛型時,泛型類型須爲引用類型,不能是基本數據類型
使用泛型時,兩邊的類型必須一致或者兩邊只有一邊用泛型(爲了保持兼容性)
自定義泛型:Java程序中的普通方法、構造方法和靜態方法中都可以使用泛型。方法使用泛形前,必須對泛形進行聲明,語法:<T>,T可以是任意字母,但通常必須要大寫。<T>通常需放在方法的返回值聲明之前。
下有兩個泛型方法:
實現交換的泛型方法:
import java.util.Arrays;
import java.util.List;
//編寫泛型方法,實現數組元素交換
public class Swap {
/**
* 將數組中指定兩個位置的元素進行交換
*/
public static <T> void swap(T[] arr,Integer pos1,Integer pos2){
T temp=arr[pos1];//記錄第一個值
arr[pos1]=arr[pos2];//交換
arr[pos2]=temp;
}
public static void main(String[] args) {
String []arr={"a","b","c"};
swap(arr,0,arr.length-1);
List list=Arrays.asList(arr);//把數組轉換爲集合
System.out.println(list);
}
}
效果:
實現顛倒順序的泛型方法:
import java.util.Arrays;
import java.util.List;
//編寫一個泛型方法,接受一個任意數組,並顛倒數組中的所有元素
public class Reserve {
public static void main(String[] args) {
Integer[] arr={1,2,3,4,5,6,7,8,9,0};
swap(arr);
List list=Arrays.asList(arr);
System.out.println(list);
}
/**
* 泛型方法的定義權限 <T>修飾符 返回值 方法名(參數列表)
* @param <T>
* @param arr
*/
public static <T> void swap(T[] arr){
int start=0;
int end=arr.length-1;
while(true){
if(start>=end){
break;
}
T temp=arr[start];
arr[start]=arr[end];
arr[end]=temp;
/*以上的操作時將首位兩個元素不斷的交換,
*直到前一個元素的下標大於等於後一個下標爲止
*/
start++;
end--;
}
}
}
效果:
如果一個類多處都要用到同一個泛型,這時可以把泛形定義在類上(即類級別的泛型),語法格式如下:
public class GenericDao<T> {
privateT field1;
publicvoid save(T obj){}
publicT getId(int id){}
}
注意:
*
在類級別上定義的泛型,只對類的非靜態成員有效
* 靜態方法不能使用類定義的泛形,而應單獨定義泛形