Re: [問題] 請問泛型的問題
※ 引述《jtorngl (DDFL)》之銘言:
: 請問 Collection 不支援 covariance (還是該說泛型不支援 covariance)
: 所以 summary 只能傳入 List<Number> 的物件
: 而不能傳入 List<Integer>、List<Double>, ...
: public double summary(List<Number> nums) {
你只能傳 List<Number>,不能傳 List<Integer> 等…
: 為了讓這段程式能達到類似 covariance 機制
: 所以會使用 wildcard
: public double wildcardSummary(List<? extends Number> nums) {
你可以傳 List<Number>、List<Integer> 等…
: 不過泛型使用 extends 一樣可以做到不是嗎
: private <E extends Number> double genericsSummary(List<E> nums) {
你必須先確定 E 真正的型態,而這個 E 只能是 Number 的子類,一旦 E 確認了
,例如 Number,那麼你就只能傳 List<Number>…
是的,這也可以解決 List<? extends Number> 能解決的問題,不過語法意義上
是不同的,只不過兩者正好涵蓋了相同的問題。
因為正好能解決相同問題,就簡潔度來說, List<? extends Number> 會是我想
要的寫法,因為只要出現一次角括號…
另一方面,若是個 instance method,通常會以類別上的型態限定為主,例如:
public class Test<E> {
public E foo(List<? extends Number> nums)
{
return null;
}
}
會在方法前使用型態限定,通常是在 static method 時,例如:
public class Test {
public static <E extends Number> Some foo(E e)
{
return null;
}
}
: 目前能想到的只有,wildcard 有 super 來達到 contravariance
: 但是泛型只支援 extends 而沒有支援 super
: 那如果沒有要 contravariance 的效果
: 有什麼情況是 wildcard 才能做到,而泛型還是不能編譯的?
不要從能不能編譯來看,很多情況其實都可以通過編譯,你要看你想解決什麼
,以及可讀性哪個比較好。
: 目前看一些文章,在方法的參數,要限制參數型態邊界時
: 幾乎都是使用 List<? extends Number>
: 好像比較少看到 <E extends Number> ... List<E>
: 看了一下 JDK 的 List interface
: boolean addAll(Collection<? extends E> c);
: 是因為限制的參數型態都是動態,才只能用 wildcard 嗎?
不是,理由上面說過,你想看到更多 <E extends Number> 的應用,可以找找
有 static method 的類別,例如 Collections..
static <T extends Object & Comparable<? super T>>
T maxCollection<? extends T> coll)
static <T extends Comparable<? super T>>
void sortList<T> list)
: 以JDK 的 List 介面來說
: public interface List<E> extends Collection<E>
: 有一個方法是 boolean containsAll(Collection<?> c);
:
: 如果是這樣定義的
: boolean containsAll(Collection<E> c);
:
: 那當我們建立 List<String> strs = Arrays.asList("1", "2");
: 那這個 strs 的 containsAll 方法,只能用來比較 String 集合了
:
: 反之因為使用 ? 定義
: boolean containsAll(Collection<?> c); 這樣定義
: 所以 strs 還是可以用來比對各種型態的集合
這就是兩者應用上的差別之一…instance method 通常會以類別上宣告的型態來限定,
因為閱讀上比較簡單。
也可以進一步看看這邊的文件:
https://openhome.cc/Gossip/JavaEssence/WildCard.html
--
良葛格學習筆記
http://openhome.cc
--
※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 39.10.69.16 (臺灣)
※ 文章網址: https://www.ptt.cc/bbs/java/M.1598789899.A.696.html
※ 編輯: JustinHere (39.10.69.16 臺灣), 08/30/2020 20:24:35
※ 編輯: JustinHere (39.10.69.16 臺灣), 08/30/2020 20:25:04
推
08/30 21:42,
4年前
, 1F
08/30 21:42, 1F
推
08/31 12:58,
4年前
, 2F
08/31 12:58, 2F
→
08/31 12:59,
4年前
, 3F
08/31 12:59, 3F
從 Java SE 9 技術手冊開始,我有把 Producer Extends,Producer Extends 的說明加
進去,這也是個理解的方向。
→
08/31 13:00,
4年前
, 4F
08/31 13:00, 4F
→
08/31 13:00,
4年前
, 5F
08/31 13:00, 5F
因為單純做 method chain,沒有變數型態可以參數,就得明確指定泛型的型態:
BeanUtil.<Student>getBean(
data, "cc.openhome.Student").getName();
若有變數型態可參考就不用,因為編譯器可以從變數的型態來推斷,例如文件中
就有個例子:
Student student = BeanUtil.getBean(data, "cc.openhome.Student");
※ 編輯: JustinHere (110.26.97.16 臺灣), 08/31/2020 17:42:52
推
08/31 18:25,
4年前
, 6F
08/31 18:25, 6F
→
08/31 18:25,
4年前
, 7F
08/31 18:25, 7F
→
08/31 18:26,
4年前
, 8F
08/31 18:26, 8F
→
08/31 18:26,
4年前
, 9F
08/31 18:26, 9F
→
08/31 18:27,
4年前
, 10F
08/31 18:27, 10F
因為你的 obtain 是:
public static <T> T obtain(T t) { return t; }
T 用在參數上,之後的呼叫中,"abc" 已經告訴編譯器,T 的型態是 String 了…
至於文件上的 static method 是:
public static <T> T getBean(Map<String, Object> data, String clzName)
之後的呼叫中,沒有任何來源可以告訴編譯器,T 的型態是什麼,你就得主動提供…
→
08/31 18:29,
4年前
, 11F
08/31 18:29, 11F
→
08/31 18:30,
4年前
, 12F
08/31 18:30, 12F
推
08/31 18:32,
4年前
, 13F
08/31 18:32, 13F
推
08/31 20:08,
4年前
, 14F
08/31 20:08, 14F
→
08/31 20:08,
4年前
, 15F
08/31 20:08, 15F
編譯時期型態推斷是一直在加強,不用一直糾結在這部份,必須得提供時就提供,只要
你不是不明就理地直接 cast 就行。
※ 編輯: JustinHere (27.247.130.217 臺灣), 09/01/2020 07:53:47
推
09/01 11:18,
4年前
, 16F
09/01 11:18, 16F
→
09/01 11:19,
4年前
, 17F
09/01 11:19, 17F
→
09/01 11:19,
4年前
, 18F
09/01 11:19, 18F
→
09/01 11:21,
4年前
, 19F
09/01 11:21, 19F
→
09/01 11:21,
4年前
, 20F
09/01 11:21, 20F
討論串 (同標題文章)
java 近期熱門文章
PTT數位生活區 即時熱門文章