前言:
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);
接下來,研究一下泛型的擦除...