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

Post on 07-Aug-2015

87 Views

Category:

Engineering

2 Downloads

Preview:

Click to see full reader

TRANSCRIPT

2015/03/31 讀書會分享

Effective Java摘選條目分享 2

- 泛型

Kane

大綱

泛型 Generic緣由

特性

泛型方法

Bounded Wildcard Type & PECS顯式、隱藏

異構

沒有泛型的日子

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

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

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

容易出錯

泛型來了

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)

特質

compile time 時消除類型資訊

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

不可變 invariant

List<Number> list = ...

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

泛型方法

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)

Example for Bounded Wildcard TypeExample:

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

想要新增 pushAll() 及 popAll()

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

放不進去

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

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

用 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

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

還是放不進去

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

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

用 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

規則:PECS

producer-extends

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

consumer-super

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

src 提供元素:生產者

dst 獲取元素:消費者

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 獲取元素進行比較,是消費者

顯式的類型參數

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

隱藏類型參數 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?

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

List<?>

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

隱藏類型參數 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)));}

異構容器 (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”

實作範例 - 利用動態 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 類型

Q & A

top related