Java泛型01:基礎知識

1. 泛型程序設計

泛型是Java程序設計中一個重要的思想,它可以被用在類、接口、方法中。泛型簡單來說就是:

1)所編寫的代碼在不用修改的前提下,可以被多種不同類型的對象所重用。

2)相較於雜亂的使用Object變量,泛型機制編寫的程序具有更好的安全性和可讀性,在效率上也會有所提升。

Java在JDK 1.5 之後增加了泛型機制,我們所熟知的 ArrayList 類就是泛型程序設計的一個典型例子。

1.1 使用泛型類的例子:ArrayList

ArrayList<String> stringList = new ArrayList<String>();

上述代碼中的 String 就是類型參數,它指明瞭 ArrayList 中存儲的數據類型爲 String 類型。也就是說,對於 stringList 而言,我們只能往裏面添加 String 類型的對象。

	String str = "";
	Integer a = 0;
	stringList.add(str); // ok
	stringList.add(a); // error

如上述例子所示,當我們向 stringList 添加其它類型的對象時,就會產生錯誤。

需要注意的是,類型參數不能是八大基本類型,如果的確需要用到它們,可以用其包裝類型替代(如用 Integer 代替int)。

JDK 1.7 之後,構造函數中的類型參數可以被省略,省略的類型可以從變量的類型推斷得出:

1.2 類型變量

在構建泛型類、泛型接口和泛型方法時,可以通過類型變量來“泛型化”數據。例如:

public class Pair<T> {
}

Pair<T> 中的 T 就是類型變量,被放在泛型類類名後面的尖括號裏。

關於類型變量,在Java庫中,常使用E、K、V、T等大寫字母表示:
E: 表示集合的元素類型
K:表示關鍵字
V:表示值(常與K對應)
T:表示“任意類型”(需要時還可以用鄰近的字母U和S)

類型變量可以定義數據域的類型、方法的參數類型以及返回值的類型。

2. 泛型類

利用類型變量,可以構建自己的泛型類。

public class Pair<T> {
	private T first; 
	private T second;
	
	public Pair() {
		first = null;
		second = null;
	} 
	
	public Pair(T first, T second) {
		this.first = first;
		this.second = second;
	}
	
	public T getFirst() {
		return first;
	} 
	
	public T getSecond() {
		return second;
	}
	
	public void setFirst (T newValue) {
		first = newValue;
	} 
	
	public void setSecond(T newValue) {
		second = newValue;
	}
	
}

泛型類 Pair 利用類型變量 T 定義了數據域的類型、方法的參數類型以及返回值的類型。在使用到Pair類時,只需要在實例化對象時用具體的類型參數替換類型變量即可。

泛型的實現利用了Java虛擬機的類型擦除機制。爲便於理解,可以將類型變量T理解成“某種變量”,在實例化泛型類時需要具體指明其類型,並用指定的類型“替換”它,以得到一個“具體的”對象。
3. 泛型接口

同樣的,我們可以構建自己的泛型接口。這裏需要注意的是, 接口中的數據域都是public static final(靜態常量),因此不能用類型變量定義。

這並不難理解,對於靜態常量而言,它的值在類或接口建立的時候就是確定的,既然如此,它肯定不能是個“類型不確定”的變量(類型都不能確定,它的值還怎麼定下來呢?)。
 

public interface Person<T> {
	T information; // error

	T getInformation(); // ok
}

對於泛型接口的實現,可以在實現時就指定類型變量的具體類型,這樣實現的類就是一個具體的類,而不是泛型類,如:

public class MyPerson implements Person<String> {
	String information;
	
	@Override
	public String getInformation() {
		return information;
	}
	
}

當然也可以在實現此接口時不具體指定類型變量的具體類型,這樣得到的就是一個泛型類,如:

public class MyPerson<T> implements Person<T> {
	T information;

	@Override
	public T getInformation() {
		return information;
	}
	
}

4. 泛型方法

除了泛型類和泛型接口,實際上,還可以在普通類中定義泛型方法(帶有類型參數的方法),例如:

public class MyPerson {
	
	public static <T> T getFirstInformation(T[] information) {
		if (information.length >= 2) {
			return information[1];
		}
		return null;
	}
	
}

從尖括號和類型變量可以看出,這是一個泛型方法。當調用泛型方法時,需要在方法名之前的尖括號中填入具體的類型,如:

	String[] information = {"111111", "ABCDD", "boy"};
	String name = MyPerson.<String>getFirstInformation(information);
	System.out.println(name);

	// 程序打印:ABCDD

需要注意的是,在定義時尖括號被放在了修飾符之後,返回類型之前;在調用時尖括號被放在了方法名之前。這樣定義的好處是可以避免語法分析的歧義。

試想如果尖括號被放在方法名之後,如方法: f<T, U>();
在調用方法時,對於g(f<a,b>(c)),是理解成函數f<a,b>(c)的返回值,還是兩個布爾變量f<a和b>(c)呢?

 

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