1 回答

TA貢獻(xiàn)1946條經(jīng)驗(yàn) 獲得超4個(gè)贊
"? super T"和"? extends T",都是java泛型通配符,而用法又有區(qū)別,
還有super 和extends 不是java類關(guān)系中的超類和繼承的意思,他是通配符的下限和上限限制.
下面看一個(gè)通配符得高級(jí)用法:
在這一部分,我們來考慮一些通配符得高級(jí)用法。我們已經(jīng)看到了上限通配符在從一個(gè)數(shù)據(jù)結(jié)構(gòu)中進(jìn)行讀取的幾個(gè)例子?,F(xiàn)在考慮相反的情況,一個(gè)只寫的數(shù)據(jù)結(jié)構(gòu)。
接口Sink是這種情況的一個(gè)簡單例子。
interface Sink<T> {
void flush(T t);
}
我們可以想象他被如下面的代碼一樣使用。方法writeAll() 被設(shè)計(jì)來把集合coll的所有元素flush到sink snk,并且返回最后一個(gè)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); // 非法的調(diào)用!!
像上面所寫,writeAll() 的調(diào)用是非法的,因?yàn)闆]有有效的類型參數(shù)可以被推斷出來。String 或 Object都不是T的合適的類型,因?yàn)镃ollection的元素和 Sink的元素必須是同樣的類型。
我們可以解決這個(gè)問題,通過使用通配符來修改writeAll()的方法簽名,如下:
<T> T writeAll(Collection<? extends T> coll, Sink<T> snk)
String str = writeAll(cs, s); //可以調(diào)用但是返回值類型錯(cuò)誤
這個(gè)調(diào)用現(xiàn)在是合法的,但是賦值產(chǎn)生錯(cuò)誤,因?yàn)橥茢喑龅姆祷刂殿愋褪?Object因?yàn)門 匹配了Sink的類型,Object。
解決方案是使用一種我們還沒有見過的有限制的通配符:有下限的通配符。語法 ? super T 表示T的一個(gè)未知的父類(或者是T自己)。這跟我們用? extends T 表示T的一個(gè)未知的子類是對(duì)應(yīng)的。
<T> T writeAll(Collection<T> coll, Sink<? super T> snk)
String str = writeAll(cs, s); // YES!!!
使用這個(gè)語法,這個(gè)調(diào)用是合法的,推斷出來的T是String,正是我們想要的。
現(xiàn)在讓我們看一個(gè)更現(xiàn)實(shí)的例子。一個(gè) java.util.TreeSet<E> 代表一個(gè)有序的元素是E類型的樹。創(chuàng)建一個(gè)TreeSet的一個(gè)方法是傳遞一個(gè) Comparator 對(duì)象給構(gòu)造函數(shù)。這個(gè)Comparator將會(huì)用來按照需要對(duì)TreeSet進(jìn)行排序。
TreeSet(Comparator<E> c)
Comparator 接口是核心:
interface Comparator<T>
假定我們要?jiǎng)?chuàng)建一個(gè) TreeSet<String> 并傳遞一個(gè)合適的 Comparator,我們需要傳一個(gè)能比較String的Comparator。這可以是一個(gè) Comparator<String>,也可以是一個(gè) Comparator<Object>。然而我們不能用Comparator<Object>來調(diào)用上面的構(gòu)造函數(shù)。我們可以使用一個(gè)有下限的通配符來得到我們需要的靈活性:
TreeSet(Comparator<? super E> c)
這允許任何可用的Comparator被傳遞進(jìn)去。
作為使用下限通配符最終的例子,讓我們來看看方法 Collections.max(),它返回一個(gè)集合中的最大的元素。
現(xiàn)在,為了讓max()能工作,傳進(jìn)來的集合中的所有元素必須實(shí)現(xiàn) Comparatable接口。而且,他們必須都能夠被彼此比較(all be comparable to each other)。第一個(gè)嘗試是:
public static <T extends Comparable<T>> T max(Collection<T> coll)
就是說,方法的參數(shù)是某一個(gè)能和自己進(jìn)行比較的T的集合。這限制太嚴(yán)格了。
為什么?考慮一個(gè)能和任何對(duì)象進(jìn)行比較的類型:
class Foo implements Comparable<Object> ...
Collection<Foo> cf = ...;
Collections.max(cf); // 應(yīng)該能工作
cf 中的每個(gè)元素都可以和每個(gè)cf中的其他元素進(jìn)行比較,因?yàn)槊總€(gè)這樣的元素都是一個(gè)Foo,它可以和任意的對(duì)象進(jìn)行比較,也可以和另一個(gè)Foo進(jìn)行比較。
但是,使用上面的方法簽名,我們發(fā)現(xiàn)這個(gè)調(diào)用被拒絕。推斷出來的類型必須是Foo,但是Foo沒有實(shí)現(xiàn)接口 Comparable<Foo>。
T 精確的(exactly)和自己能比較是不需要的。所需要的是 T能夠和它的父類中的一個(gè)進(jìn)行比較,這導(dǎo)出:(注:Collections.max()的實(shí)際方法簽名更復(fù)雜,我們?cè)诘?0部分再討論。)
public static <T extends Comparable<? super T>> T max(Collection<T> coll)
這個(gè)推論對(duì)大多數(shù)想讓 Comparable 對(duì)任意類型生效的用法中都有效:你總是應(yīng)該使用 Comparable<? super T>。
總之,如果你有一個(gè)只使用類型參數(shù)T作為參數(shù)的API,它的使用應(yīng)該利用下限通配符( ? super T )的好處。相反的,如果API只返回T,你應(yīng)該使用上限通配符( ? extends T )來給你的客戶端更大的靈活性。
添加回答
舉報(bào)