本題對於"? super T"和"? extends T",我從書上摘個經典的例子給妳看看,如果不能理解,那麽妳就參考以下書籍慢慢體會,循序漸進!
"? super T"和"? extends T",都是java泛型通配符,而用法又有區別,
還有super 和extends 不是java類關系中的超類和繼承的意思,他是通配符的下限和上限限制.
下面看壹個通配符得高級用法:
在這壹部分,我們來考慮壹些通配符得高級用法。我們已經看到了上限通配符在從壹個數據結構中進行讀取的幾個例子。現在考慮相反的情況,壹個只寫的數據結構。
接口Sink是這種情況的壹個簡單例子。
interface Sink<T> {
void flush(T t);
}
我們可以想象他被如下面的代碼壹樣使用。方法writeAll() 被設計來把集合coll的所有元素flush到sink snk,並且返回最後壹個flush的元素。
public static <T> T writeAll(Collection<T> coll, Sink<T> snk) {
T last = null;
for (T t : coll) {
last = t;
snk.flush(last);
}
return last;
}
Sink<Object> s;
Collection<String> cs;
String str = writeAll(cs, s); // 非法的調用!!
像上面所寫,writeAll() 的調用是非法的,因為沒有有效的類型參數可以被推斷出來。String 或 Object都不是T的合適的類型,因為Collection的元素和 Sink的元素必須是同樣的類型。
我們可以解決這個問題,通過使用通配符來修改writeAll()的方法簽名,如下:
<T> T writeAll(Collection<? extends T> coll, Sink<T> snk) { … }
String str = writeAll(cs, s); //可以調用但是返回值類型錯誤
這個調用現在是合法的,但是賦值產生錯誤,因為推斷出的返回值類型是 Object因為T 匹配了Sink的類型,Object。
解決方案是使用壹種我們還沒有見過的有限制的通配符:有下限的通配符。語法 ? super T 表示T的壹個未知的父類(或者是T自己)。這跟我們用? extends T 表示T的壹個未知的子類是對應的。
<T> T writeAll(Collection<T> coll, Sink<? super T> snk) { … }
String str = writeAll(cs, s); // YES!!!
使用這個語法,這個調用是合法的,推斷出來的T是String,正是我們想要的。
現在讓我們看壹個更現實的例子。壹個 java.util.TreeSet<E> 代表壹個有序的元素是E類型的樹。創建壹個TreeSet的壹個方法是傳遞壹個 Comparator 對象給構造函數。這個Comparator將會用來按照需要對TreeSet進行排序。
TreeSet(Comparator<E> c)
Comparator 接口是核心:
interface Comparator<T> { int compare(T fst, T snd); }
假定我們要創建壹個 TreeSet<String> 並傳遞壹個合適的 Comparator,我們需要傳壹個能比較String的Comparator。這可以是壹個 Comparator<String>,也可以是壹個 Comparator<Object>。然而我們不能用Comparator<Object>來調用上面的構造函數。我們可以使用壹個有下限的通配符來得到我們需要的靈活性:
TreeSet(Comparator<? super E> c)
這允許任何可用的Comparator被傳遞進去。
作為使用下限通配符最終的例子,讓我們來看看方法 Collections.max(),它返回壹個集合中的最大的元素。
現在,為了讓max()能工作,傳進來的集合中的所有元素必須實現 Comparatable接口。而且,他們必須都能夠被彼此比較(all be comparable to each other)。第壹個嘗試是:
public static <T extends Comparable<T>> T max(Collection<T> coll)
就是說,方法的參數是某壹個能和自己進行比較的T的集合。這限制太嚴格了。
為什麽?考慮壹個能和任何對象進行比較的類型:
class Foo implements Comparable<Object> {...} ...
Collection<Foo> cf = ...;
Collections.max(cf); // 應該能工作
cf 中的每個元素都可以和每個cf中的其他元素進行比較,因為每個這樣的元素都是壹個Foo,它可以和任意的對象進行比較,也可以和另壹個Foo進行比較。
但是,使用上面的方法簽名,我們發現這個調用被拒絕。推斷出來的類型必須是Foo,但是Foo沒有實現接口 Comparable<Foo>。
T 精確的(exactly)和自己能比較是不需要的。所需要的是 T能夠和它的父類中的壹個進行比較,這導出:(註:Collections.max()的實際方法簽名更復雜,我們在第10部分再討論。)
public static <T extends Comparable<? super T>> T max(Collection<T> coll)
這個推論對大多數想讓 Comparable 對任意類型生效的用法中都有效:妳總是應該使用 Comparable<? super T>。
總之,如果妳有壹個只使用類型參數T作為參數的API,它的使用應該利用下限通配符( ? super T )的好處。相反的,如果API只返回T,妳應該使用上限通配符( ? extends T )來給妳的客戶端更大的靈活性。
(原文:This reasoning applies to almost any usage of Comparable that is intended to work for arbitrary types: You always want to use Comparable<? super T>.
In general, if you have an API that only uses a type parameter T as an argument, its uses should take advantage of lower bounded wildcards (? super T). Conversely, if the API only returns T, you'll give your clients more flexibility by using upper bounded wildcards (? extends T). )。
如果妳想比較深刻的了解java泛型那麽
建議妳看看<Java1.5泛型指南>
中文鏈接地址:/j2se/1.5/pdf/generics-tutorial.pdf