[英]Upper-Bounded and Lower-Bounded Wildcards in return type of Java Generic method
[英]Generic lower unbound vs upper bounded wildcards
import java.util.List;
import java.util.ArrayList;
interface Canine {}
class Dog implements Canine {}
public class Collie extends Dog {
public static void main(String[] args){
List<Dog> d = new ArrayList<Dog>();
List<Collie> c = new ArrayList<Collie>();
d.add(new Collie());
c.add(new Collie());
do1(d); do1(c);
do2(d); do2(c);
}
static void do1(List<? extends Dog> d2){
d2.add(new Collie());
System.out.print(d2.size());
}
static void do2(List<? super Collie> c2){
c2.add(new Collie());
System.out.print(c2.size());
}
}
這個問題的答案告訴我,當一個方法采用通配符泛型類型時,可以訪問或修改集合,但不能同時訪問或修改它們。 (凱西和伯特)
這是什么意思' 當一個方法采用通配符泛型類型時,可以訪問或修改集合,但不能同時訪問或修改它們 ?
據我所知,方法do1有List<? extends Dog> d2
List<? extends Dog> d2
所以只能訪問d2但不能修改。 方法d2有List<? super Collie> c2
List<? super Collie> c2
所以可以訪問和修改c2並且沒有編譯錯誤。
您無法將Cat
添加到List<? extends Animal>
List<? extends Animal>
因為你不知道是什么類型的列表。 那也可能是List<Dog>
。 所以你不想把Cat
扔進Black Hole
。 這就是為什么不允許modification
List
聲明的方式。
同樣當你從List<? super Animal>
取出一些東西時List<? super Animal>
List<? super Animal>
,你不知道你會得到什么。 你甚至可以得到一個Object
或Animal
。 但是,您可以在此List
安全地添加Animal
。
我將您的代碼粘貼到我的IDE中。 在do1
中發出以下錯誤信號:
類型List中的方法add(捕獲#1-of?extends Dog)不適用於參數(Collie)
當然,這是預期的。
你根本無法將Collie
添加到List<? extends Dog>
List<? extends Dog>
因為這個引用可能包含例如List<Spaniel>
。
我將您的代碼粘貼到IDEONE http://ideone.com/msMcQ中 。 它沒有為我編譯 - 這是我的預期。 您確定沒有任何編譯錯誤嗎?
這個問題的答案告訴我,當一個方法采用通配符泛型類型時,可以訪問或修改集合,但不能同時訪問或修改它們。 (凱西和伯特)
這是一個公平的第一近似值,但不太正確。 更正確的是:
您只能將null添加到Collection<? extends Dog>
Collection<? extends Dog>
因為它的add方法帶有參數? extends Dog
? extends Dog
。 無論何時調用方法,都必須傳遞屬於聲明的參數類型的子類型的參數; 但對於參數類型? extends Dog
? extends Dog
,如果表達式為null
,編譯器只能確保參數是兼容類型。 但是,您當然可以通過調用clear()
或remove(Object)
修改集合。
另一方面,如果你從一個Collection<? super Dog>
讀取Collection<? super Dog>
Collection<? super Dog>
,它的迭代器有返回類型? super Dog
? super Dog
。 也就是說,它將返回作為某種未知超類型Dog
的子類型的對象。 但不同的是,Collection可以是僅包含String
實例的Collection<Object>
。 因此
for (Dog d : collection) { ... } // does not compile
所以我們唯一知道的是返回Object的實例,即迭代這樣一個Collection的唯一類型正確的方法
for (Object o : collection) { ... }
但是可以從集合中讀取,你只是不知道你會得到什么類型的對象。
我們可以很容易地將該觀察推廣到:給定
class G<T> { ... }
和
G<? extends Something> g;
我們只能將null傳遞給聲明類型為T
方法參數,但我們可以調用返回類型為T
方法,並為結果分配一個Something
類型的變量。
另一方面,為
G<? super Something> g;
我們可以將Something
類型的任何表達式傳遞給聲明類型為T
方法參數,並且我們可以調用返回類型為T
方法,但只將結果賦給Object
類型的變量。
總而言之,對通配符類型的使用的限制僅取決於方法聲明的形式,而不取決於方法的作用。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.