[英]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>
的子類型-盡管類型String
和Object
具有此類子類型層次結構。
因此,我們在這里嘗試的是:
List<? super String>
List<? super String>
到List<String>
=>失敗,沒有子類型 List<? super String>
List<? super String>
到List<Object>
=>失敗,沒有子類型 List<? super String>
List<? super String>
到List
=>成功,因為使用原始類型通常會從類型檢查中退出 List<? super String>
List<? super String>
到List<?>
=>的操作成功,因為List<?>
是所有List<...>
的超類型 List<? super String>
List<? super String>
到List<? super String>
List<? super String>
=>成功,因為... 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.