3 回答

TA貢獻1836條經驗 獲得超5個贊
通過聲明,GenericMethod<? super ClassB>
您將聲明該類型是未知類型,它是 ClassB(或 ClassB 本身)的超類。并要求編譯器只允許將這種未知類型的子類型添加到列表中。
編譯器知道的唯一兼容子類型是 ClassB 和 ClassB 的任何子類型。創建實例時,通常最好避免使用通配符。
對于方法參數,通配符使您可以更靈活地接受哪些內容。使用PECS
(生產者=擴展,消費者=超級) 來確定使用哪個。?

TA貢獻1820條經驗 獲得超9個贊
該? super
子句是下限通配符。但界限是在推斷的類型參數上,而不是對可以傳遞給采用該泛型類型參數的方法的參數類型的限制。
當您說 時<? super ClassB>
,您表明類型參數可以是ClassB
或 任何超類型,例如ClassA
或Object
。
編譯器必須將該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
。
您的困惑在于兩個概念的合并:允許哪些類型參數以及使用類型參數的方法中允許哪些類型的對象。使用通配符會限制類型參數,但該方法仍然接受類型參數或子類型的類型。

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>,更有意義一些。
添加回答
舉報