Effective Java Item29 優先使用泛型
整理Effective Java書中Item 29: Favor generic types心得筆記
主旨
本篇就是實際教你怎麼完成泛型的教學
範例
先從一個基本的物件導向堆疊的程式碼來說明,其中elements目前是以Object來做宣告,當我們呼叫pop()取得裡面的資料時必須要進行cast轉型,這個轉型動作在運行環境中是有可能發生ClassCastException的隱憂。
public class Stack {
private Object[] elements;
private int size = 0;
private static final int DEFAULT_INITIAL_CAPACITY = 16;
public Stack() {
elements = new Object[DEFAULT_INITIAL_CAPACITY];
}
public void push(Object e) {
ensureCapacity();
elements[size++] = e;
}
public Object pop() {
if (size == 0)
throw new EmptyStackException();
Object result = elements[--size];
elements[size] = null; // Eliminate obsolete reference
return result;
}
public boolean isEmpty() {
return size == 0;
}
private void ensureCapacity() {
if (elements.length == size)
elements = Arrays.copyOf(elements, 2 * size + 1);
}
}
開始針對上面程式碼進行調整成泛型化,首先第一步是在class的部分增加一個或多個參數類型public class Stack<E>
,通常會取E
這個字表示集合的資料類型,下一步就可以把Object都替換成E。
public class Stack<E> {
private E[] elements;
private int size = 0;
private static final int DEFAULT_INITIAL_CAPACITY = 16;
public Stack() {
elements = new E[DEFAULT_INITIAL_CAPACITY];
}
public void push(E e) {
ensureCapacity();
elements[size++] = e;
}
public E pop() {
if (size == 0)
throw new EmptyStackException();
E result = elements[--size];
elements[size] = null; // Eliminate obsolete reference
return result;
}
// no changes in isEmpty or ensureCapacity
}
這時候的程式碼會出現錯誤告訴你elements = new E[DEFAULT_INITIAL_CAPACITY];
是不合法的沒辦法這樣宣告。這時候再繼續調整。
方法 1 在建構子的地方進行轉型,並加上消除unchecked的警告
@SuppressWarnings("unchecked")
public Stack() {
elements = (E[]) new Object[DEFAULT_INITIAL_CAPACITY];
}
方法 2 將elements宣告由 E[] 改為 Object[] ,並且在pop取出資料的地方進行轉型,並加上消除unchecked的警告
public class Stack<E> {
private Object[] elements;
private int size = 0;
private static final int DEFAULT_INITIAL_CAPACITY = 16;
public Stack() {
elements = new Object[DEFAULT_INITIAL_CAPACITY];
}
public E pop() {
if (size == 0)
throw new EmptyStackException();
@SuppressWarnings("unchecked")
E result = (E) elements[--size];
elements[size] = null; // Eliminate obsolete reference
return result;
}
// no changes in isEmpty or ensureCapacity
}
兩種方法都是可行的,但是方法1造成heap pollution的問題讓工程師會偏向使用方法2的技術(JDK原始碼也是)
小結
主要還是鼓勵盡可能使用泛型取代強制轉型更安全。
Read other posts