前言:

  java的泛型上下限不是很好理解,尤其像我這種菜雞。反反覆覆看了好幾遍了...,真是...

一、簡單的繼承體系

class Person{}

class Student extends Person{}

class Worker extends Person{}

二、泛型上限(extends 關鍵字)

public static void upperBound(List<? extends Person> list, Person p){
//正確,因為null沒有型別資訊
list.add(null);
//錯誤,因為list的引數型別可能是Person的子類
list.add(p);①
//成功獲取
if(list.size() > 0){
Person pp = list.get(0);②
}
}

  ①處的錯誤在於list的引數型別是不確定的,其引數型別可能是 Person的子類,子類集合(List)不能新增父類的元素。測試如下:

public static void testUpperBound(){
ArrayList<Student> slist = new ArrayList<Student>();
Person p = new Person();
upperBound(slist, p);//無法新增成功
}

  如何解決泛型上限新增問題,可以使用泛型方法,如下:

public static <T extends Person> void upperBound2(List<T> list, T p){
list.add(p);
}
public static void testUpperBound2(){
ArrayList<Person> plist = new ArrayList<Person>();
Person p = new Person();
Student s = new Student();
upperBound2(plist, p); upperBound2(plist, s);
}

  也就是說,使用泛型上限add方法時,集合引數型別 和 元素引數型別 要一致,這樣新增的時候才不會有矛盾。看一下eclipse中對upperBound2(plist, s);這個函式呼叫的提示,如下:

  可見,T型別最終會解析為 泛型的最上限型別,Student s相應的向上轉型。

  接著說 ② 處,為什麼能獲取成功呢?泛型上限嘛,至少上限的型別是確定的,所有的上限型別的子類都可以進行向上轉型,自然獲取是不成問題了。

三、泛型的下限

public static void lowerBound(List<? super Student> list){
Person var = new Person();
//錯誤,list的引數型別可能是 Student,這樣就不能新增父類Person了,所以 變數var的型別 必須是 Student或者 Student的子類
list.add(p);①
//正確
Student s = new Student();
list.add(s);
}
public static void testlowerBound(){
ArrayList<Person> list = new ArrayList<Person>();
lowerBound(list);
}

  ①處新增失敗,告訴我們,泛型下限使用add方法新增元素時,元素的引數型別必須是 下限 或者 下限的子型別。否則會出現子類集合新增父類元素。

public static void lowerBound2(List<? super Person> list){
Person p = new Person();
list.add(p);
//獲取,不能編譯
Person as = list.get(0);①
}
public static void testlowerBound2(){
ArrayList<Person> list = new ArrayList<Person>();
lowerBound2(list);
}

  ①處獲取失敗了,我們看一下eclipse提示我們該怎麼辦?

  將 第二個方法 將"as"的型別更改為"Object"  和 泛型的下限 結合一下考慮一下,add(e)方法在正確新增後,都會成為Object物件,在使用get(index)方法時,會轉換為

? super Person型別(可能是Person型別,也可能是Person的父類型別,甚至是Object),執行Person as = list.get(0),那麼就有了 向下轉型。java中無法保證向下轉型是安全的。所以①處不能編譯。

四、泛型上限最常見的一個應用

List<Person> plist = new ArrayList<Person>();
List<Student> slist = new ArrayList<Student>(); plist.addAll(slist);

五、泛型下限最常見的一個應用

Set<Student> set = new TreeSet<Student>(new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
return 0;
}
});

六、泛型上下限一個綜合的例子

  注:個人瞎掰的...,就是將上面兩個例子結合在一起!

Set<Person> set = new TreeSet<Person>(new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
return 0;
}
});
List<Student> slist = new ArrayList<Student>();
List<Worker> wlist = new ArrayList<Worker>();
set.addAll(slist);
set.addAll(wlist);

  接下來,研究一下泛型的擦除...