簡單理解Java泛型

聲明一個泛型類並實例化

Box是一個泛型類,這裏的T是參數傳遞給泛型類的泛型,它可以是任何對象。而t則是T的一個實例。個人理解泛型,就是泛化類型,將具體的類型用統一的類指代。add和get是定義的兩個方法。

public class Box<T>{
	private T t;
	public void add(T t){
		this.t = t;
	}
	public void get(T t){
		return t;
	}
}

在main方法中,泛型類這樣使用。其中intbox和strbox都是泛型類的對象,可以調用泛型類中已定義的方法。

Box<Integer> intbox = new Box<Integer>();
Box<String> strbox = new Box<String>();
intbox.add(new Integer(1));
System.out.println(intbox.get());
//調用了泛型類中的方法,打印數字1

泛型類可以有多個類型參數,這就使得泛型可以當C++中的結構體來使用。當然,憑我現有的知識,結構體與類並無本質的差異。同時,可以用參數化類型來代替,比如傳的不只是一個類,而是某個框架,如下例。

public static void main(String[] args){
	Box<Integer,String> box = new Box<Integer,String>();
	box.add(Integer.valueOf(100),"hello world");

	Box2<Integer,List<String>> box2 = new Box2<Integer,List<String>>();
	List<String> m = new ArrayList<String>();
	m.add("Hello");m.add("world");
	box2.add(Integer.valueOf(10),m);//此時的m是一個列表
}
class Box<T,S>{
	private T t;
	private S s;
	public void add(T t,S s){
		this.t = t;
		this.s = s;
	}
}

參數命名約定 也就是尖括號裏的字母,這是一般的約定並無強制要求

字符 意義
E 由Java集合框架使用(list等)
K 表示映射中的鍵值(key)
V 表示映射中的值(value)
N 表示數字
T 第一類通用參數
S 第二類通用參數
U 第三類通用參數
V 第四類通用參數

有界類型參數

什麼是泛型有界類型參數?就是限制允許傳遞給類型參數的類型。簡單來說就是給泛型一定的條件,比如只允許接受Char類或者它的子類實例。要聲明它,只需要後跟extend關鍵字和邊界上限即可。如果需要多重邊界,則用&連接。

public static <T extends Number & Comparable<T>> T maximum(T x,T y,T z){
	T max = x;
	if(y.compareTo(max)>0){
		max = y;
	}
	if(z.compareTo(max)>0){
		max = z;
	}
	return max;
}
public static void main(String[] args){
	System.out.println(maximum(10,20,30));
	System.out.println(maximum(22.1,33.2,44.3));
}

Java在List、Set、Map中都提供了泛型的支持,語法如下

List<T> list = new ArrayList<T>();
Set<T> set = new HashSet<T>();
Map<T> map = new HashMap<T>();

通配類型符

首先要知道,爲什麼需要通配類型?《Java語言程序設計》中有一個例子。

public static void main(String[] args){
	GenericStack<Integer> intstack = new GenericStack<Integer>();
	intstack.push(1);intstack.push(2);
	System.out.println(max(intstack));
}
public static double max(GenericStack<Number> stack){
	double max = stack.pop().doubleValue();
	while(!stack.empty()){
		double value = stack.pop().doubleValue();
		if(value>max)max=value;
	}
	return max;
}

這段程序會出現編譯錯誤,原因是雖然Integer是Number的子類,但GenericStack<Integer>不是GenericStack<Number>的子類。因此需要通配符規避這種錯誤。
?表示非受限通配符
?extend T 表示T或T的一個未知子類
?super T 表示T或T的一個父類

public static double max(GeericStack<? extends Number> stack)就可以改正上面的錯誤。


泛型類型擦除

泛型是使用一種稱爲類型消除的方法來實現的。編譯器使用泛型類型信息來編譯代碼,但是隨後會消除它。因此,泛型信息在運行時是不可用的。這種方法可以使泛型代碼向後兼容使用原始類型的遺留代碼。
泛型在編譯的時候一旦確認其是安全的,就會將它轉換爲原始類型。不管實際的具體類型是什麼,泛型類是被它所有實例共享的。


限制

不能使用E object = new E();,因爲運行時泛型類型E是不可用的。同理不能創建數組。
異常類不能是泛型。
靜態環境下不允許類的參數是泛型類型。
除非由無界通配符進行參數化,否則不允許轉換爲參數化類型。如下段代碼。

private static void add(Box<?> box){
	Box<Integer> intbox = (Box<Integer>) box;
}

無法用instanceof驗證。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章