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

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

Java泛型方法返回類型中的上界和下界通配符

Java泛型方法返回類型中的上界和下界通配符

Cats萌萌 2021-12-10 10:48:21
我試圖解決一個我無法理解部分答案的問題。以下是課程BackLister:public class BackLister {    // INSERT HERE    {        List<T> output = new LinkedList<T>();        for (T t : input)            output.add(0, t);        return output;    }}問題問哪個可以插入// INSERT HERE到BackLister類中編譯運行沒有錯誤?以下是選項:A. public static <T> List<T> backwards(List<T> input)B. public static <T> List<T> backwards(List<? extends T> input)C. public static <T> List<T> backwards(List<? super T> input)D. public static <T> List<? extends T> backwards(List<T> input)E. public static <T> List<? super T> backwards(List<T> input)F. public static <? extends T> List<T> backwards(List<T> input)G. public static <? super T> List<T> backwards(List<T> input)據我所知,A和B是正確的,對于for (T t : input)工作中的元素input應該是類型T或亞型T。但我不明白為什么D和E選項是正確的?我明白以下幾點:public static <T> List<? extends T> backwards(List<T> input) 意味著返回類型應該是List的T或 的子類T。public static <T> List<? super T> backwards(List<T> input)意味著返回類型應該是List的T或超類T。有人可以幫我理解嗎?
查看完整描述

3 回答

?
瀟瀟雨雨

TA貢獻1833條經驗 獲得超4個贊

它們中的每一個都存在差異,我將解釋其中的大部分。讓我們從我們的例子開始。我使用這個類層次結構:


class Food {}

class Apple extends Food {}

class Orange extends Food {}

class RedApple extends Apple {}


List<Food> listFood = new ArrayList<>();

List<Apple> listApple = new ArrayList<>();

List<Orange> listOrange = new ArrayList<>();

List<RedApple> listRedApple = new ArrayList<>();

現在從第一個開始:


A. public static <T> List<T> backwards(List<T> input)

這個方法只會接受List<T>和返回List<T>,你不能發送listApple和返回listRedApple。(但是您的返回列表可以包含,RedApple因為它擴展Apple但列表類型必須是List<Apple>,沒有別的)


B. public static <T> List<T> backwards(List<? extends T> input)

您可以發送listRedApple和返回,listApple但您知道這listRedApple是“?擴展 Apple”,因此在方法主體中 java 將 T 識別為 Apple。然后,如果你使用可以添加的元素listRedApple,其發送作為參數,你可以添加Apple在listRedApple其中是不正確的!所以編譯器避免它并給出編譯錯誤。在 B 中,您只能讀取元素(并將其作為 T 獲?。荒芟蚱渲刑砑尤魏蝺热?。


C. public static <T> List<T> backwards(List<? super T> input) 

您可以發送listApple,然后在方法主體中添加任何擴展,Apple因為編譯器將 T 視為 TApple的任何列表,并且在T的任何超列表中,您可以添加任何擴展Apple。

但是這一次,您無法讀取任何內容,因為您不知道它的類型,除非您將其作為Object. (這是一個“?超級T”的列表)


正如你在這里看到的,有區別嗎?超級和?延伸。其中之一為您提供寫訪問權限,另一個為您提供讀訪問權限。這就是通配符的真正用途。


D. public static <T> List<? extends T> backwards(List<T> input)

E. public static <T> List<? super T> backwards(List<T> input)   

如果您發送listApple然后您返回,List<? extends Apple>但您可以將它分配給任何listFood或listApple或listRedApple因為List<? extends Apple>可能包含Apple或RedApple或其他東西,我們不能將它分配給任何List<T>因為然后我們可以添加T到該列表中,并且可能T和? extends T不一樣。這對D和都是一樣的E。您可以將其分配給List<? extends Apple>for 'E 和List<? super Apple>forD并將它們發送到需要它們作為參數的方法。


F. public static <? extends T> List<T> backwards(List<T> input)

G. public static <? super T> List<T> backwards(List<T> input)

給出編譯錯誤,因為不能像這樣使用通配符。


我希望這對你有幫助。

如果有什么問題,任何評論都表示贊賞。


查看完整回答
反對 回復 2021-12-10
?
慕神8447489

TA貢獻1780條經驗 獲得超1個贊

選項D和E是有效的,因為泛型類型之間存在超子類型關系,允許您定義方法可以接受或返回的更大的類型集。


因此,以下是有效的 (D):


public static <T> List<? extends T> backwards(List<T> input) {

    return List.of();

}


// there exist a super-subtype relationships among List<? extends Number> and List<Long>

List<? extends Number> list = backwards(List.<Long>of(1L, 2L));

因為該類型Long是通配符所? extends Number表示的類型家族的成員(作為其子類型的類型家族Number和類型Number本身)。


下一個代碼片段也是有效的 (E):


public static <T> List<? super T> backwards(List<T> input) {

    return List.of();

}


List<? super Long> ints = backwards(List.<Long>of(1L, 2L));

因為該類型Long是通配符所? super Long表示的類型家族的成員(作為超類型的類型家族Long和類型Long本身)。


所以,你的理解是對的。


查看完整回答
反對 回復 2021-12-10
?
幕布斯6054654

TA貢獻1876條經驗 獲得超7個贊

下圖描述了泛型中的子類型關系:


List<T> is a subtype of List<? super T>

Also List<T> is a subtype of List<? extends T>

這就是為什么選項 D 和 E 是正確的。

http://img1.sycdn.imooc.com//61b2c02900017f4d03350197.jpg

您可以參考該頁面:https : //docs.oracle.com/javase/tutorial/java/generics/subtyping.html


查看完整回答
反對 回復 2021-12-10
  • 3 回答
  • 0 關注
  • 281 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

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

幫助反饋 APP下載

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

公眾號

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