2016-09-14 165 views
1

Java的8方法簽名如下所示:Java的泛型方法,通配符列表返回類型

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

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

result = m(list); 

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

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

我的問題是,爲什麼result可以是理由t raw List,甚至不能是List<Object>

+0

例如,我問爲什麼我的'結果'不能成爲'List '或'List '。它可以只是原始的'List'。 – bladekp

+0

爲什麼你使用通配符作爲返回類型?這是一個相當奇怪的事情... – fge

+0

@fge那是庫方法,不是我的。 – bladekp

回答

2

調用帶有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<String> =>失敗,無分型
  2. 分配List<? super String>List<Object> =>失敗,無分型
  3. 分配一個List<? super String>List =>成功,因爲使用原始類型通常從類型檢查中選擇出來
  4. List<? super String>指定爲List<?> =>成功,因爲List<?>是所有List<...>
  5. 的超分配List<? super String>List<? super String> =>成功,因爲...好...
  6. 分配List<? super String>List<? ectends Object> =>成功,因爲List<? ectends Object>是基本上與List<?>相同。

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

這是爲什麼?編譯器不能保證實際列表實例化的類型與約束條件? super/extends CharSequence相匹配。

1

你不能這樣做的原因是因爲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()); 

幸運的是,上述不不編譯。