Java 學習筆記——泛型

1. 定義一個泛型類

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 void setFirst(T first) {
		this.first = first;
	}

	public T getFirst() {
		return first;
	}

	public void setSecond(T second) {
		this.second = second;
	}

	public T getSecond() {
		return second;
	}

}

    類型變量 T 表示任意類型(也可以用臨近的字母 U、S 表示),Java 中使用 E 表示集合元素類型,K,V 分別表示表的 關鍵字和值 類型。可以定義多個類型變量如 class Pair<T,U>{ ... } 類型變量用逗號隔開。

2. 定義泛型方法

@SuppressWarnings("unchecked")
public static <T> T getMiddle(T... a) {
	return a[a.length / 2];
}

3. 限定類型變量

public static <T extends Comparable<T>> T min(T[] a) {
	if (a == null || a.length == 0)
		return null;
	T smallest = a[0];
	for (int i = 1; i < a.length; i++)
		if (smallest.compareTo(a[i]) > 0)
			smallest = a[i];
	return smallest;
}

    如果限定多個類型,則用符號 & 隔開,如 <T extends Comparable<T> & Serializable>,限定類型的順序影響類型擦除後表示的類型,取第一個限定類型作爲擦除後類型。比如 <T extends Comparable<T> & Serializable> 類型擦除後會用 Comparable 類替換 T。

4. 泛型類的類型擦除

    在 Java 虛擬機中,不存在泛型類型對象,所有的對象都屬於普通的類。定義一個泛型類型,會自動提供一個對應的原始類型,原始類型名是去掉泛型類型變量後的類名,並擦除類型變量,替換成限定的類型(沒有限定類型就是 Object)。比如 Pair<T> 泛型類的原始類型是:

class Pair {
	private Object first;
	private Object second;

	public Pair() {
		first = null;
		second = null;
	}

	public Pair(Object first, Object second) {
		this.first = first;
		this.second = second;
	}

	public void setFirst(Object first) {
		this.first = first;
	}

	public Object getFirst() {
		return first;
	}

	public void setSecond(Object second) {
		this.second = second;
	}

	public Object getSecond() {
		return second;
	}

}

    當程序調用泛型方法時,會先調用原始類型的方法,再強制類型轉換成需要的類型。如:

Pair<Employee> buddies = new Pair<Employee>();
Employee employee = buddies.getFirst();

    buddies.getFirst() 返回 Object 類型,然後強制轉換成 Employee 類型

5. 泛型方法的類型擦除

    泛型方法的類型擦除也是把類型變量轉換成限定類型,無限定類型就是 Object,如:

// 泛型方法
public void <T> method(T extends Comparable param) {}
// 類型擦除後
public void Comparable method(Comparable param){}
    如果泛型類的子類想要覆蓋父類方法,編譯器會在子類中生成一個橋方法,用於實現覆蓋父類方法,例如:
class DateInterval extends Pair<Date> {
	@Override
	public void setSecond(Date second) {
		if (second.compareTo(getFirst()) >= 0)
			super.setSecond(second);
	}
}
    編譯器會在 DateInterval 類中生成橋方法
public void setSecond(Object second) {
	setSecond((Date)second);
}

    通過橋方法實現覆蓋父類的 setSecond 方法。原因是 DateInterval 類在類型擦除後,從父類繼承的 setSecond 方法是:public void setSecond(Object second){},而自身的setSecond(Date second){} 並沒有覆蓋掉父類的 setSecond 方法(方法名相同,方法參數(順序、類型)不同,屬於方法重載),所以編譯器通過橋方法實現方法的覆蓋。

6. 通配符

    符號 ? 表示通配符,使用通配符爲泛型類指定子類型和父類型,例如 Pair<Manager>Pair<? extendsEmployee> 的子類,而 Pair<Manager> 和 Pair<Employee> 之間並沒有關係,雖然 Manager 是 Employee 的子類。Pair<? super Manager> 用於指定父類。

    注:通配符不是類型變量,比如 Pair<?> 的 ? getFirst() 是非法的。

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