effectiveJava

類型參數和通配符的選擇

這篇文章是我在學習Item31的時候 自己提出來的問題 上網找到解答之後 覺得有必要記錄下來 才產生了這篇文章

問題

如同Item31最後一小章的問題

這兩個差在哪

public static <E> void swap(List<E> list, int i, int j);

public static void swap(List<?> list, int i, int j);

還有以下的其他聲明 差在哪

public boolean containsAll(Collection<?> c);

public <T> boolean containsAll(Collection<T> c);
public boolean addAll(Collection<? extends E> c);

public <T extends E> boolean addAll(Collection<T> c);
public static <T> void copy(List<T> dest, List<? extends T> src)

public static <T, S extends T> void copy(List<T> dest, List<S> src)

如果以上的聲明 你都知道差別以及使用時機 那讀者可以跳過這篇文章

類型參數和通配符

兩者區別與使用時機

1.通配符只能讀取 不能添加

所以要取決於你內部的實作 如果你需要在List裡面加一個東西 就不能用通配符

public static <E> void funct1(final List<E> list1, final E something) {
  list1.add(something);
}
public static void funct2(final List<?> list, final Object something) {
  list.add(something); // does not compile
}

記得: 能加進List<?>的只有null

2.如果你想要在一個聲明裡面表明兩個類別的關係 那就要用類型參數

比如說

public static <T extends Number> void copy(List<T> dest, List<T> src)

你要明確的表示dest跟src同一個類型 就只能用以上方式 以下方式沒用

public static void copy(List<? extends Number> dest, List<? extends Number> src)

這樣有可能dest是List<Integer>但是src是List<Double>

3.你想要多重限制一個類型(Multiple bound) 那只能用類型參數

public static <T extends Comparable & Serializable> void copy()

以下方式不行

public static <? extends Comparable & Serializable> void copy()

4.你想支持類型下限的限制

你用類型參數 你就只能限制上限extends

public <T extends Integer> void genericExtend(List<T> list){}

不能限制下限

//Compile不過
public <T super Integer> void genericSuper(List<T> list){}

如果是wildcard 上下限都ok

public void wildCardSuper(List<? super Integer> list){}
public void wildCardExtend(List<? extends Integer> list){}

5.如果這個類型 在函數裡面也有用到 那就當然只能用類型參數

public void pushAll(Iterable<E> src) {
  for (E e : src)
    push(e);
}

6.如果一個聲明裡面 類型參數只出現過一次 那就改成通配符 這在Item31也有提到

結論

能用通配符就盡量用通配符 但如果你的函示需要

1.實作中需要寫入(消費者)

2.一個聲明裡面表明兩個類別的關係

3.多重限制(Multiple bound)

4.函數的實作本身 也需要使用到同一個類型

那你就必需要使用類型參數

參考資料

When to use generic methods and when to use wild-card?

Difference between generic type and wildcard type