簡體   English   中英

Java通用方法,通配符List返回類型

[英]Java generic methods, wildcard List return type

Java的8種方法簽名如下所示:

public static <E extends CharSequence> List<? super E> m(List<E> list);

在代碼中的某個地方,方法調用:

result = m(list);

假設我已經如下創建參數list

List<String> list = new ArrayList<>();

我的問題是,為什么result只能是原始List ,甚至不能是List<Object>

List<String>作為參數調用您的方法就像調用以下方法:

public static List<? super String> m(List<String> list) { ... }

考慮以下起始代碼:

List<String> list = new ArrayList<>();
List<? super String> result = m(list);

這將調用上述方法,並將返回值存儲到變量result -該變量的值必須與方法的返回類型完全相同。

現在的問題是:可以將此變量分配給哪些變量,或者更好地分配給哪種類型? 因此,我們正在談論分配兼容性。

考慮以下任務:

List<String> result1 = result; // compiler error: type mismatch (not assignable)
List<Object> result2 = result; // compiler error: type mismatch (not assignable)

List result3 = result; // ok
List<?> result4 = result; // ok

List<? super String> result5 = result; // ok
List<? extends Object> result6 = result; // ok

要了解此錯誤的性質,您必須知道泛型是不變的 這意味着,類型List<String> 不是 List<Object>的子類型-盡管類型StringObject具有此類子類型層次結構。

因此,我們在這里嘗試的是:

  1. 分配List<? super String> List<? super String>List<String> =>失敗,沒有子類型
  2. 分配List<? super String> List<? super String>List<Object> =>失敗,沒有子類型
  3. 分配List<? super String> List<? super String>List =>成功,因為使用原始類型通常會從類型檢查中退出
  4. 分配List<? super String> List<? super String>List<?> =>的操作成功,因為List<?>是所有List<...>的超類型
  5. 分配List<? super String> List<? super String>List<? super String> List<? super String> =>成功,因為...
  6. 分配List<? super String> List<? super String>List<? ectends Object> List<? ectends Object> =>成功,因為List<? ectends Object> List<? ectends Object>本質上與List<?>相同。

注意,試圖分配一個List<? super String> List<? super String>List<? super CharSequence> List<? super CharSequence>List<? extends CharSequence> List<? extends CharSequence>也會失敗。 它們不在子類型層次結構中。

為什么會這樣? 編譯器不能保證實際的列表使用與約束匹配的類型實例化? super/extends CharSequence ? super/extends CharSequence

之所以不能這樣做,是因為Java泛型不是協變的。 也就是說, List<Object> 不是 List<String>的超類。 但是,方法m的方法簽名將允許返回List<String> ,然后您將得到一個List<Object>類型的引用,該引用指向List<String> 由於泛型類型信息在運行時不可用,因此不會立即引發異常,但是可能會在不相關的地方導致類型錯誤。

例如,假設m實現如下:

private static List<CharSequence> theResult = new ArrayList<>();

public static <E extends CharSequence> List<? super E> m(List<E> list) {
    theResult.addAll(list);
    return theResult;
}

然后,使用以下方法將一個非CharSequence對象添加到List<CharSequence>

List<Object> os = m(someList);
os.add(new Object());

幸運的是,上面沒有編譯。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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