[問題] 請問泛型的問題

看板java作者 (DDFL)時間4年前 (2020/08/29 12:31), 4年前編輯推噓0(0020)
留言20則, 2人參與, 4年前最新討論串1/2 (看更多)
請問 Collection 不支援 covariance (還是該說泛型不支援 covariance) 所以 summary 只能傳入 List<Number> 的物件 而不能傳入 List<Integer>、List<Double>, ... public double summary(List<Number> nums) { double total = 0; for (Number num : nums) { total += num.doubleValue(); } return total; } 為了讓這段程式能達到類似 covariance 機制 所以會使用 wildcard public double wildcardSummary(List<? extends Number> nums) { double total = 0; for (Number num : nums) { total += num.doubleValue(); } return total; } 不過泛型使用 extends 一樣可以做到不是嗎 private <E extends Number> double genericsSummary(List<E> nums) { double total = 0; for (Number num : nums) { total += num.doubleValue(); } return total; } 目前能想到的只有,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 嗎? 補充一下,問這個問題主要是,目前開始接觸 sonarcube 這類工具 對於程式會有很多規範,雖然目前還沒去看是否有泛型語法的 issue 只是想先問一下,實際開發時,是否在需要限制參數邊界時 一律使用 wildcard,而不要用泛型宣告 -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 114.43.70.113 (臺灣) ※ 文章網址: https://www.ptt.cc/bbs/java/M.1598675517.A.17E.html ※ 編輯: jtorngl (114.43.70.113 臺灣), 08/29/2020 12:36:01

08/29 13:14, 4年前 , 1F
在你舉的method參數,只用在一個地方的情況下,兩個一樣
08/29 13:14, 1F

08/29 13:15, 4年前 , 2F

08/29 13:16, 4年前 , 3F
methods.html 官方文件是建議在這個情況下用wildcard
08/29 13:16, 3F

08/29 13:19, 4年前 , 4F
wildcard才能做到的如你說的就是下限(super),另外就是不需
08/29 13:19, 4F
自己在寫時都沒有限定參數邊界過 一直都是用 public <E> void process(List<E> datas) 最近看了某些 API 的 source,突然才想到一直沒搞懂泛性這塊 查了一些資料,看到 covariant、contravariant、invariant 現在反而更混亂,有一種若要直接下結論的話 反正就是要限定參數邊界時,不管上限或下限,用 wildcard 就對了

08/29 13:19, 4年前 , 5F
要type parameter可以直接用在field、local variable
08/29 13:19, 5F

08/29 13:30, 4年前 , 6F
而generic的type parameter可以用在多個參數,可有多個上限
08/29 13:30, 6F
請問不需要 type parameter 可以直接用在 field 是什麼意思 泛型可以用在 field,但這句話不是指 wildcard 可以用在 field 吧? 感謝說明

08/30 02:00, 4年前 , 7F
wildcard可以用在field沒錯啊,上面的網頁最下面也有範例
08/30 02:00, 7F

08/30 02:03, 4年前 , 8F
generic要用在field,必須要class有type parameter
08/30 02:03, 8F

08/30 02:05, 4年前 , 9F
而wildcard可直接用像 class A {List<? extends B> list;}
08/30 02:05, 9F

08/30 02:06, 4年前 , 10F
如果不是真的需要generic class,這時wildcard就比較適合
08/30 02:06, 10F

08/30 02:09, 4年前 , 11F
而method部分也不是wildcard就對了,上面也說了限制有多個
08/30 02:09, 11F

08/30 02:12, 4年前 , 12F
或多個參數時就只能用generic
08/30 02:12, 12F

08/30 02:14, 4年前 , 13F
其實兩個語意就是有差,wildcard是未知,頂多加上一些限制
08/30 02:14, 13F

08/30 02:18, 4年前 , 14F
generic是寫其他程式用到再決定,但用到後就是確定的
08/30 02:18, 14F

08/30 02:55, 4年前 , 15F
更正一下最後兩個generic → type parameter
08/30 02:55, 15F
感謝 ssccg 大的說明 如果先不論語法,編譯檢查等 單純只論為什麼要用 wildcard 以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 還是可以用來比對各種型態的集合 我想一開始會不懂 <T> 和 ? 的差別 應該是在 "定義" 和 "使用" 沒搞清楚差別 1. ? 必須用在已經使用在 <T> 定義好的類別之,只是它可是任意型態 2. 在 generics class,<T> 和 ? 的使用就會有如上面 containsAll 的差別 但是在泛型方法中,應該就沒有泛型類別上的限制 public class XyzUtil { public static <T> void process(T t) { System.out.println(t); } } 在使用 process(T t) 時,每次呼叫方法時,才決定參數的型態 所以這時候使用 <T> 和 ? 的行為就是一樣的 也就是此時的 T 也相當於任意型態,不知這樣理解對嗎 因為一直以來我都只有使用 generics method 所以覺得 <T> 和 ? 不是一樣的東西嗎 除了在限制參數邊界時,? 可以使用 super 只是我會用 <T extends Number> 之類別,卻還沒用過 super 所以也就一直沒研究 <T> 和 ? 的差別 ※ 編輯: jtorngl (114.43.70.113 臺灣), 08/30/2020 16:48:07

08/31 11:54, 4年前 , 16F
Producer Extends, Consumer Super 關鍵字,可以參考一
08/31 11:54, 16F

08/31 11:54, 4年前 , 17F
08/31 11:54, 17F

08/31 12:48, 4年前 , 18F
對我來說,通常不用去管泛型類別時,我會選擇用wildcard
08/31 12:48, 18F

08/31 12:48, 4年前 , 19F
,例如:Collections#swap,交換List中的元素根本不需要
08/31 12:48, 19F

08/31 12:48, 4年前 , 20F
知道裡面裝了什麼類別的元素
08/31 12:48, 20F
感謝說明,也有在看 <? exends T> 和 <? super T> 原本只是以為單純的設定型別的上下界 但是還有 set 和 get 使用上的限制,而且有點不好懂 我才知道原來自己對泛型的理解還很淺 像是 Number[] nums = new Integer[3]; // ok List<Number> nums = new ArrayList<Integer>(); // compile error 語法的限制,或是編譯器的限制等等的細節 都沒去理解,還有得學 ※ 編輯: jtorngl (111.249.70.26 臺灣), 08/31/2020 13:08:52
文章代碼(AID): #1VITez5- (java)
文章代碼(AID): #1VITez5- (java)