effective java 摘選條目分享 2 - 泛型

22
2015/03/31 讀書會分享 Effective Java 摘選條目分享 2 - 泛型 Kane

Upload: kane-shih

Post on 07-Aug-2015

87 views

Category:

Engineering


2 download

TRANSCRIPT

Page 1: Effective java   摘選條目分享 2 - 泛型

2015/03/31 讀書會分享

Effective Java摘選條目分享 2

- 泛型

Kane

Page 2: Effective java   摘選條目分享 2 - 泛型

大綱

泛型 Generic緣由

特性

泛型方法

Bounded Wildcard Type & PECS顯式、隱藏

異構

Page 3: Effective java   摘選條目分享 2 - 泛型

沒有泛型的日子

List list = new ArrayList();list.add(“string”);list.add(new Foo());

String item1 = (String) list.get(0);Foo item2 = (Foo) list.get(1);

依賴於程式設計師之間的約定

容易出錯

Page 4: Effective java   摘選條目分享 2 - 泛型

泛型來了

List<String> list = new ArrayList<String>();list.add(“string1”);list.add(new Foo()); // compile error

String item1 = list.get(0);Foo item2 = list.get(1); // compile error

由 compiler 保證類型安全 (type-safe)

Page 5: Effective java   摘選條目分享 2 - 泛型

特質

compile time 時消除類型資訊

(E[]) list.toArray(); // warning: unchecked type

不可變 invariant

List<Number> list = ...

list.add(new Integer(10)); // compile error

Page 6: Effective java   摘選條目分享 2 - 泛型

泛型方法

public static <T> boolean isNull(T[] array) { return (array == null);}

isNull(new String[1]);isNull(new Foo[2]);

T: typeE: collectionK, V: map

?: wildcard (any)

Page 7: Effective java   摘選條目分享 2 - 泛型

Example for Bounded Wildcard TypeExample:

class Stack { public Stack(); public void push(E e); public E pop(); public boolean isEmpty();}

想要新增 pushAll() 及 popAll()

Page 8: Effective java   摘選條目分享 2 - 泛型

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

Page 9: Effective java   摘選條目分享 2 - 泛型

放不進去

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

Stack<Number> stack = …Iterable<Integer> integers = …stack.pushAll(integers); // compile error

Page 10: Effective java   摘選條目分享 2 - 泛型

用 extends 限制參數類型

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

public void pushAll(Iterable<? extends E> src)

Stack<Number> stack = …Iterable<Integer> integers = …stack.pushAll(integers); // compile error

Page 11: Effective java   摘選條目分享 2 - 泛型

popAll() impl.public void popAll(Collection<E> dst) { while (!isEmpty()) dst.add(pop());}

Page 12: Effective java   摘選條目分享 2 - 泛型

還是放不進去

public void popAll(Collection<E> dst) { while (!isEmpty()) dst.add(pop());}

Stack<Number> stack = …Collection<Object> objects = …stack.popAll(objects); // compile error

Page 13: Effective java   摘選條目分享 2 - 泛型

用 super 限制參數類型

public void popAll(Collection<E> dst) { while (!isEmpty()) dst.add(pop());}

public void pushAll(Collection<? super E> dst)

Stack<Number> stack = …Collection<Object> objects = …stack.popAll(objects); // compile error

Page 14: Effective java   摘選條目分享 2 - 泛型

規則:PECS

producer-extends

public void pushAll(Iterable<? extends E> src)

consumer-super

public void popAll(Collection<? super E> dst)

src 提供元素:生產者

dst 獲取元素:消費者

Page 15: Effective java   摘選條目分享 2 - 泛型

PECS:幫你解決轉換的困擾

public static <T extends Comparable<T>> T max(List<T> list) {

public static <T extends Comparable<? super T>> T max(List<? extends T> list)

max() 裡面用到:

1. Iterator<T> i = list.iterator();

2. t.compareTo(result)

list 提供元素,是生產者

t 獲取元素進行比較,是消費者

Page 16: Effective java   摘選條目分享 2 - 泛型

顯式的類型參數

public static <E> Set<E> union(Set<? extends E> s1, Set<? extends E> s2)

Set<Integer> integers = …Set<Double> doubles = …Set<Number> numbers = union(integers, doubles); // compile error

Set<Number> numbers = Union.<Number>union(integers, doubles);

static method, 所以放 class name

Page 17: Effective java   摘選條目分享 2 - 泛型

隱藏類型參數 1/3public static <E> void swap(List<E> list, int i, int j)

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

Which one is better?

Page 18: Effective java   摘選條目分享 2 - 泛型

隱藏類型參數 2/3public static void swap(List<?> list, int i, int j) { list.set(i, list.set(j, list.get(i))); // compile error}

List<?>

compiler 完全不知道裡面放什麼類型

Page 19: Effective java   摘選條目分享 2 - 泛型

隱藏類型參數 3/3public static void swap(List<?> list, int i, int j) { swapHelper(list, i, j);}

// for wildcard captureprivate static <E> void swapHelper(List<E> list, int i, int j) { list.set(i, list.set(j, list.get(i)));}

Page 20: Effective java   摘選條目分享 2 - 泛型

異構容器 (heterogeneous container)Type Token 概念,以 type 為 key 存取值

public class Favorite { public <T> void putFavorite(Class<T> type, T instance); public <T> T getFavorite(Class<T> type);}

fav.put(String.class, “XD”);fav.put(Integer.class, 20);

fav.get(String.class); “XD”

Page 21: Effective java   摘選條目分享 2 - 泛型

實作範例 - 利用動態 castpublic class Favorite {

private Map<Class<?>, Object> favorites = new HashMap<Class<?>, Object>();

public <T> void putFavorite(Class<T> type, T instance) {

// check type null

favorites.put(type, type.cast(instance));

}

public <T> T getFavorite(Class<T> type) {

return type.cast(favorites.get(type));

}

}

若 client 誤用,可拋出ClassCastException

拿出來是 Object 類型,但回傳值要求 T 類型

Page 22: Effective java   摘選條目分享 2 - 泛型

Q & A