SlideShare a Scribd company logo
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: type
E: collection
K, V: map
?: wildcard (any)
Example for Bounded Wildcard Type
Example:
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/3
public 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/3
public static void swap(List<?> list, int i, int j) {
list.set(i, list.set(j, list.get(i))); // compile error
}
List<?>
compiler 完全不知道裡面放什麼類型
隱藏類型參數 3/3
public static void swap(List<?> list, int i, int j) {
swapHelper(list, i, j);
}
// for wildcard capture
private 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”
實作範例 - 利用動態 cast
public 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

More Related Content

PPTX
Understanding Python decorators
TXT
Suma de n numeros
PDF
Java & le pattern matching
PDF
BABELで、ES2015(ES6)を学ぼう!
PDF
Testování prakticky
PPT
从问题开始,前端,架构、框架与库的实战
DOCX
Convert bilangan
PDF
Arrays and Functions in JavaScript
Understanding Python decorators
Suma de n numeros
Java & le pattern matching
BABELで、ES2015(ES6)を学ぼう!
Testování prakticky
从问题开始,前端,架构、框架与库的实战
Convert bilangan
Arrays and Functions in JavaScript

What's hot (11)

PPTX
Java лаб13
PDF
Comprendre la programmation fonctionnelle, Blend Web Mix le 02/11/2016
PDF
Prof.js
KEY
珠三角技术沙龙新语言场 C++11
PPT
Spring Framework Orm Di
PDF
Compiler programming in c# report
PPTX
Librerias de c++
PPTX
for loops
DOCX
โปรแกรมย่อยและฟังก์ชันมาตรฐาน
DOC
Palindromo no recursivo
ODP
Mikstura it2013
Java лаб13
Comprendre la programmation fonctionnelle, Blend Web Mix le 02/11/2016
Prof.js
珠三角技术沙龙新语言场 C++11
Spring Framework Orm Di
Compiler programming in c# report
Librerias de c++
for loops
โปรแกรมย่อยและฟังก์ชันมาตรฐาน
Palindromo no recursivo
Mikstura it2013
Ad

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

  • 3. 沒有泛型的日子 List list = new ArrayList(); list.add(“string”); list.add(new Foo()); String item1 = (String) list.get(0); Foo item2 = (Foo) list.get(1); 依賴於程式設計師之間的約定 容易出錯
  • 4. 泛型來了 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)
  • 5. 特質 compile time 時消除類型資訊 (E[]) list.toArray(); // warning: unchecked type 不可變 invariant List<Number> list = ... list.add(new Integer(10)); // compile error
  • 6. 泛型方法 public static <T> boolean isNull(T[] array) { return (array == null); } isNull(new String[1]); isNull(new Foo[2]); T: type E: collection K, V: map ?: wildcard (any)
  • 7. Example for Bounded Wildcard Type Example: class Stack { public Stack(); public void push(E e); public E pop(); public boolean isEmpty(); } 想要新增 pushAll() 及 popAll()
  • 8. pushAll() impl. public void pushAll(Iterable<E> src) { for (E e : src) push(e); }
  • 9. 放不進去 public void pushAll(Iterable<E> src) { for (E e : src) push(e); } Stack<Number> stack = … Iterable<Integer> integers = … stack.pushAll(integers); // compile error
  • 10. 用 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
  • 11. popAll() impl. public void popAll(Collection<E> dst) { while (!isEmpty()) dst.add(pop()); }
  • 12. 還是放不進去 public void popAll(Collection<E> dst) { while (!isEmpty()) dst.add(pop()); } Stack<Number> stack = … Collection<Object> objects = … stack.popAll(objects); // compile error
  • 13. 用 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
  • 14. 規則:PECS producer-extends public void pushAll(Iterable<? extends E> src) consumer-super public void popAll(Collection<? super E> dst) src 提供元素:生產者 dst 獲取元素:消費者
  • 15. 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 獲取元素進行比較,是消費者
  • 16. 顯式的類型參數 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
  • 17. 隱藏類型參數 1/3 public 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?
  • 18. 隱藏類型參數 2/3 public static void swap(List<?> list, int i, int j) { list.set(i, list.set(j, list.get(i))); // compile error } List<?> compiler 完全不知道裡面放什麼類型
  • 19. 隱藏類型參數 3/3 public static void swap(List<?> list, int i, int j) { swapHelper(list, i, j); } // for wildcard capture private static <E> void swapHelper(List<E> list, int i, int j) { list.set(i, list.set(j, list.get(i))); }
  • 20. 異構容器 (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”
  • 21. 實作範例 - 利用動態 cast public 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 類型
  • 22. Q & A