亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

試圖理解超級通配符在Java泛型中的作用

試圖理解超級通配符在Java泛型中的作用

溫溫醬 2023-11-01 20:57:24
我正在閱讀這篇文章來了解通配符在泛型中的作用super。我明白如何extends運作,但我很難理解super我有一個擴展ClassA,使ClassB超ClassA類ClassB。如果我正確理解這篇文章,則將<? super ClassB>允許任何屬于ClassB.我有以下代碼GenericMethod.javapublic class GenericMethod<T> {    private List<T> list;    public GenericMethod() {        list = new ArrayList<>();    }    public void add(T t) {        list.add(t);    }    public T get(int index) {        return list.get(index);    }}Driver.javapublic class Driver {    public static void main(String[] args) {        GenericMethod<? super ClassB> genericMethod = new GenericMethod<>();        ClassA classA = new ClassA();        genericMethod.add(classA); // Compile-time error here    }}錯誤The method add(capture#1-of ? super ClassB) in the type GenericMethod<capture#1-of ? super ClassB> is not applicable for the arguments (ClassA)我不明白我哪里錯了。當我實例化該類時GenericMethod,我已經聲明它將接受任何帶有聲明的超類型值。因此,類內部應該接受所有擴展的類。ClassB<? super ClassB>TGenericMethodClassB那么為什么該add方法會拋出編譯時錯誤呢?該方法不應該add已經知道它正在傳遞一個完全兼容的類型嗎?
查看完整描述

3 回答

?
一只甜甜圈

TA貢獻1836條經驗 獲得超5個贊

通過聲明,GenericMethod<? super ClassB>您將聲明該類型是未知類型,它是 ClassB(或 ClassB 本身)的超類。并要求編譯器只允許將這種未知類型的子類型添加到列表中。

編譯器知道的唯一兼容子類型是 ClassB 和 ClassB 的任何子類型。創建實例時,通常最好避免使用通配符。

對于方法參數,通配符使您可以更靈活地接受哪些內容。使用PECS(生產者=擴展,消費者=超級) 來確定使用哪個。?


查看完整回答
反對 回復 2023-11-01
?
慕妹3146593

TA貢獻1820條經驗 獲得超9個贊

? super子句是下限通配符。但界限是在推斷的類型參數上,而不是對可以傳遞給采用該泛型類型參數的方法的參數類型的限制。

當您說 時<? super ClassB>,您表明類型參數可以是ClassB或 任何超類型,例如ClassAObject。

編譯器必須將該add方法視為可以是以下任何簽名:

add(Object t)
add(ClassA t)
add(ClassB t)

ClassA(如果直接從另一個類繼承而不是繼承的話,可能還有其他類型Object)。

編譯器必須拒絕將 aClassA作為 的參數,add因為類型參數可能被推斷為ClassB。GenericMethod<ClassB>將 a 分配給變量是合法的genericMethod。

GenericMethod<? super ClassB> genericMethod = new GenericMethod<ClassB>();

但是能夠將 a 傳遞ClassA給需要 a 的方法是沒有意義的ClassB。

事實上,這就是菱形算子 - 的推斷ClassB。

您的困惑在于兩個概念的合并:允許哪些類型參數以及使用類型參數的方法中允許哪些類型的對象。使用通配符會限制類型參數,但該方法仍然接受類型參數或子類型的類型。


查看完整回答
反對 回復 2023-11-01
?
慕桂英3389331

TA貢獻2036條經驗 獲得超8個贊

我承認這有點違反直覺,但從編譯器的角度來看,這是有道理的。

假設您以這種方式定義一個列表:

List<? super ClassB> myList;

你得到了

ClassB extends ClassA;
ClassC extends ClassA;

你能做嗎?

ClassA a = new ClassC();
myList.add (a);//does not compile

不,有幾個原因。首先是因為最終在運行時,參數化類型變成了具體的單一類型。因此,實際上您不能將A 類對象與 B 類對象混合。

其次,因為編譯器必須檢查您插入的任何內容是否可強制轉換為ClassB。因此,只需添加一個 ClassB 對象(或他的子類型),即可履行合同。但事實并非總是如此!ClassA 對象不能是 ClassB 的超類型。

即對象“a”實際上是一個ClassC對象!

這就是為什么你不能添加超類型。所以它只允許您添加 ClassB 對象 - 或子類型 -

如果將對象“a”轉換為 ClassB,則會編譯,但在運行時會失敗并出現ClassCastException

ClassA a = new ClassC();
myList.add((ClassB) a); //Compiles but fails at runtime

同時,通配符與super結合,可以作為方法的形參。IE:

void printValues (List<? super ClassB> list)

這種方式允許對超級 B 類集合的處理進行一般化,從而使以下調用成為可能:

List<Object> lo;
List<ClassA> la;
...
printValues (lo);
printValues (la);

在本例中,定義使用通配符,例如 <? super ClassB>,更有意義一些。


查看完整回答
反對 回復 2023-11-01
  • 3 回答
  • 0 關注
  • 136 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號