關於泛型萬用字元邊界的疑惑及解疑

2021-08-15 00:21:00 字數 2173 閱讀 5748

void set(? extends someclass);

? extends someclass get(); 

我們使用萬用字元通常是希望某乙個例項可以向上轉型 例:

listlist = new arraylist() //compile error 

list<? extends animal> list = new arraylist()  //compile ok

這些是基本的概念,在這兒我就不再概述為什麼了,我們要講的是為什麼上界限定(? extends someclass)使用set方法

編譯錯誤,而使用get方法卻是安全的呢?

讓我們先考慮一下陣列,假如你以如下的形式建立了乙個陣列.

animal ani = new dog(10); //compile ok

利用了向上轉型的多型思想,這是完全合法的 現在我們設想向裡面新增元素。

ani[0] = new dog() //compile ok ,runtime ok

ani[1] = new animal() //compile ok , runtime error

我們知道現在操縱的是dog型別的陣列,但是編譯器不知道(只有在執行時,ani引用才和dog陣列建立聯絡),編譯的時候編譯器沒

有理由會拒絕存放animal型別的物件,因為他本身就是乙個animal型別的引用。

陣列擁有特殊的保護機制,即使在編譯時期插入了錯誤的物件,執行時也能發現並丟擲這些異常,所以也沒必要為此擔心什麼。

現在假設你運用的是泛型,你能不能這樣做呢? 現在考慮如下例子

list<? extends animal> list = new arraylist() //compile ok

這也是向上轉型。

但有一點和陣列不同的是,陣列在編譯階段就確定了他是什麼型別的陣列引用(如上例是animal型別的陣列引用),而帶泛型的list呢?他只知道他是乙個某型別的list引用,只知道這個「某型別」是繼承自animal的類,具體是dog,cat,還是monkey呢,他一無所知。

你可能會提出疑問,後面不是跟了 new arraylist() 嗎,這不是在告訴他他是乙個dog型別的arraylist引用嗎?很遺憾,編譯器沒有那麼聰明,這些只會在執行時建立聯絡,然而執行時的型別擦除又讓他們攜帶的資訊煙消雲散,你也就無法期待這些東西在執行時會給你什麼驚喜了。

那如果想向我們剛建好list裡面新增元素呢 如add(new dog()) 或者add(new animal())   (和set一樣,在此以add為例更好)

list.add(new dog())    //compile error

list.add(new animal()) //compile error

編譯器拒絕一切為其新增元素的操作(傳參操作),為什麼?因為 list<? extends animal> list 無法確定他具體是什麼類,就像list只能為其新增animal及animal的子類元素一樣,你乙個連具體是什麼類都不知道的引用,編譯器自然認為任何新增都是不安全的。

讓我們再舉個容易理解的例子,我們暫時僅僅只觀察這個式子-------list

<? extends animal> 現在我們假設?是cat,那麼我們能做些什麼?

我們能向裡面新增 cat和cat的子類元素,但是我們不能新增dog,monkey甚至是animal元素。

那現在返回來,編譯器無法得知 ? 具體是什麼型別,那 ?可能是cat,也可能是dog 或者其他的繼承自animal的類,我們又怎麼能確定哪些add是安全的,哪些add是非法的呢?

所以我們自然無法使用add或者set方法。

我們知道get方法返回乙個值,這個值只要是確定的編譯器就可以接受,現在考慮如下例子

listtest = new arraylist(); 

test.add(new cat());

list<? extends animal> list = test; 

animal ani = list.get(0); //compile ok,runtime ok

get方法為什麼合理? 因為他有乙個確定的返回值。 ? extends animal 的返回值一定是乙個animal型別的 如果你對這句話有異議,那我建議你再回去溫習一下有關多型的知識,這確實是多型的乙個體現,不管你?是代表cat dog 還是monkey 這些類的共通點就是他們都是繼承自animal的,這點編譯器心知肚明,自然也就不會有任何異議和不確定性,所以get方法確實是合理的

泛型的萬用字元

萬用字元 wildcard 例如 public class testwildcards 舉例 想要宣告乙個方法,可以把乙個collection集合src中的所有元素,新增到另乙個collection集合dest中 public void copy collection src,collection ...

泛型的萬用字元

當使用泛型類或者泛型介面,傳遞的資料中,泛型的型別不確定,可以通過通 配符表示。一旦程式使用了泛型的萬用字元後,只能使用object類中的共性的 方法,集合中自身元素的方法無法使用。萬用字元的基本使用 泛型的萬用字元 不知道使用什麼型別來接受的時候,此時可以使用 代表未知 的萬用字元。此時只能接受資...

泛型萬用字元 與 有限制的泛型萬用字元

一 泛型萬用字元 子父類關係 list list1 newarraylist list list2 newarraylist list1 list2 編譯錯誤 list list null list list1 list list2 結論 讀寫問題 collection c newarraylist...