effective java 摘選條目分享 2 - 泛型
TRANSCRIPT
![Page 1: Effective java 摘選條目分享 2 - 泛型](https://reader034.vdocuments.mx/reader034/viewer/2022042508/55c3e30abb61ebf7538b464d/html5/thumbnails/1.jpg)
2015/03/31 讀書會分享
Effective Java摘選條目分享 2
- 泛型
Kane
![Page 2: Effective java 摘選條目分享 2 - 泛型](https://reader034.vdocuments.mx/reader034/viewer/2022042508/55c3e30abb61ebf7538b464d/html5/thumbnails/2.jpg)
大綱
泛型 Generic緣由
特性
泛型方法
Bounded Wildcard Type & PECS顯式、隱藏
異構
![Page 3: Effective java 摘選條目分享 2 - 泛型](https://reader034.vdocuments.mx/reader034/viewer/2022042508/55c3e30abb61ebf7538b464d/html5/thumbnails/3.jpg)
沒有泛型的日子
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 - 泛型](https://reader034.vdocuments.mx/reader034/viewer/2022042508/55c3e30abb61ebf7538b464d/html5/thumbnails/4.jpg)
泛型來了
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 - 泛型](https://reader034.vdocuments.mx/reader034/viewer/2022042508/55c3e30abb61ebf7538b464d/html5/thumbnails/5.jpg)
特質
compile time 時消除類型資訊
(E[]) list.toArray(); // warning: unchecked type
不可變 invariant
List<Number> list = ...
list.add(new Integer(10)); // compile error
![Page 6: Effective java 摘選條目分享 2 - 泛型](https://reader034.vdocuments.mx/reader034/viewer/2022042508/55c3e30abb61ebf7538b464d/html5/thumbnails/6.jpg)
泛型方法
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 - 泛型](https://reader034.vdocuments.mx/reader034/viewer/2022042508/55c3e30abb61ebf7538b464d/html5/thumbnails/7.jpg)
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 - 泛型](https://reader034.vdocuments.mx/reader034/viewer/2022042508/55c3e30abb61ebf7538b464d/html5/thumbnails/8.jpg)
pushAll() impl.public void pushAll(Iterable<E> src) { for (E e : src) push(e);}
![Page 9: Effective java 摘選條目分享 2 - 泛型](https://reader034.vdocuments.mx/reader034/viewer/2022042508/55c3e30abb61ebf7538b464d/html5/thumbnails/9.jpg)
放不進去
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 - 泛型](https://reader034.vdocuments.mx/reader034/viewer/2022042508/55c3e30abb61ebf7538b464d/html5/thumbnails/10.jpg)
用 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 - 泛型](https://reader034.vdocuments.mx/reader034/viewer/2022042508/55c3e30abb61ebf7538b464d/html5/thumbnails/11.jpg)
popAll() impl.public void popAll(Collection<E> dst) { while (!isEmpty()) dst.add(pop());}
![Page 12: Effective java 摘選條目分享 2 - 泛型](https://reader034.vdocuments.mx/reader034/viewer/2022042508/55c3e30abb61ebf7538b464d/html5/thumbnails/12.jpg)
還是放不進去
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 - 泛型](https://reader034.vdocuments.mx/reader034/viewer/2022042508/55c3e30abb61ebf7538b464d/html5/thumbnails/13.jpg)
用 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 - 泛型](https://reader034.vdocuments.mx/reader034/viewer/2022042508/55c3e30abb61ebf7538b464d/html5/thumbnails/14.jpg)
規則: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 - 泛型](https://reader034.vdocuments.mx/reader034/viewer/2022042508/55c3e30abb61ebf7538b464d/html5/thumbnails/15.jpg)
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 - 泛型](https://reader034.vdocuments.mx/reader034/viewer/2022042508/55c3e30abb61ebf7538b464d/html5/thumbnails/16.jpg)
顯式的類型參數
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 - 泛型](https://reader034.vdocuments.mx/reader034/viewer/2022042508/55c3e30abb61ebf7538b464d/html5/thumbnails/17.jpg)
隱藏類型參數 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 - 泛型](https://reader034.vdocuments.mx/reader034/viewer/2022042508/55c3e30abb61ebf7538b464d/html5/thumbnails/18.jpg)
隱藏類型參數 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 - 泛型](https://reader034.vdocuments.mx/reader034/viewer/2022042508/55c3e30abb61ebf7538b464d/html5/thumbnails/19.jpg)
隱藏類型參數 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 - 泛型](https://reader034.vdocuments.mx/reader034/viewer/2022042508/55c3e30abb61ebf7538b464d/html5/thumbnails/20.jpg)
異構容器 (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 - 泛型](https://reader034.vdocuments.mx/reader034/viewer/2022042508/55c3e30abb61ebf7538b464d/html5/thumbnails/21.jpg)
實作範例 - 利用動態 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 - 泛型](https://reader034.vdocuments.mx/reader034/viewer/2022042508/55c3e30abb61ebf7538b464d/html5/thumbnails/22.jpg)
Q & A