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() 是非法的。