1 class People{}; 2 class Student extends People{}; 3 class teacher extends People{}; 4 //創建一個List,目的是將它用來存儲所有繼承自People基類的對象實例,但實際上我們無事可做! 5 List<? extends People> list = new ArrayList<Student>(); 6 //list.add(new Student()); //compile error 7 //list.add(new People()); //compile error 8 //list.add(new Object()); //compile error
從上面可以看出,無論我們是add一個基類實例還是派生類實例到list中都會發生編譯錯誤,這是為什么呢?
我們看下面這個例子:
print(list.indexof(new Fruit())); //ok! return -1, the argument is Object
對比一下,我們發現add()接受一個具有泛型參數類型的參數,但是indexof將接受Object類型的參數。當我們創建一個List<? extends People>時,addd的參數也同步變成了<? extends People>.但是從這樣的描述中,編譯器並不能了解到這里到底需要People的哪個具體子類型,因此它不會接受任何類型的Fruit,甚至是Object類型。---因此,編譯器直接拒絕 對參數列表中設計通配符的方法(比如:add())的調用.
這就是這個compile eror的原因!
那么怎么解決這個問題呢? 我們可以使用超類型通配符,通過調用方法指定<? super Myclass>,甚至使用類型參數<? super T>,這樣就可以安全的傳遞一個類型對象到泛型類型中了,這在java中稱之為 “逆變”,
1 static <T> void method1(List<? super T> list, T item){ 2 list.add(item); 3 } 4 static void test1(){ 5 List<Fruit> list = new ArrayList<Object>(); 6 method1(list, new Apple()); 7 method1(list, new Orange()); 8 list.add(new Blanla()); //一般用法 9 for (Fruit fruit : list) { 10 println(fruit.getClass().toString()); 11 } 12 } 13 14 Output: 15 class demo5.Apple 16 class demo5.Orange 17 class demo5.Blanla
<? super Fruit>表示list所持有的類型為Fruit與Fruit的基類中的某一類型,以上面這個例子為例,Apple和Orange必定是這某一類型的子類,所以add方法能正確的被調用,從上面可以看出,extends定義了泛型的上界,而super確定了泛型的下界。