簡體   English   中英

通用較低的未綁定與上限有界通配符

[英]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> ,你不知道你會得到什么。 你甚至可以得到一個ObjectAnimal 但是,您可以在此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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM