2020/08/22

[筆記] Effective Java #29 優先考慮泛型

Effective Java 3rd 簡體中文版筆記 #29 優先考慮泛型
一般在使用泛型方法,並不會太難,像是 collection 系列,但若要將自己編寫的 class 支援泛型就會稍難一點。接著會試著列出 class 泛型化的步驟。
  1. 在 class 宣告處新增類型參數
  2. 將 class 中要取代的類型換成類型參數
// Object-based collection - a prime candidate for generics
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;
    }
    
    private void ensureCapacity() {
        if (elements.length == size)
            elements = Arrays.copyOf(elements, 2 * size + 1);
    }
}
上面的範例,在每次調用 pop 後需將 Object 轉換,來試著將它泛型化。在將 E[] elements 生成時改成 new E[DEFAULT_INITIAL_CAPACITY] 會有編譯錯誤,E 的未知型態無法用在陣列上。這時可以改成生成時使用 Object 陣列,然後強制轉換成 E 陣列,像是 (E[]) new Object[DEFAULT_INITIAL_CAPACITY],但這樣的寫法會產生 unchecked 警告,確認該狀況是允許的,可以加上 @SuppressWarnings("unchecked") 解除警告。
第二種方式,是將 element 保持宣告為 Object 陣列,這樣在生成時就不需要轉換,而是在 pop 方法進行轉換,像是 E result = (E) elements[--size],同時也需要 @SuppressWarnings("unchecked") 來解除警告。
public class Stack<E> {
    private E[] elements;
    private int size = 0;
    private static final int DEFAULT_INITIAL_CAPACITY = 16;
    
    @SuppressWarnings("unchecked")
    public Stack() {
        elements = (E[]) new Object[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;
    }
}
第一種方式較易讀,在未來有更多方法時,不需要頻繁的將 Object 轉換成 E,但這樣會有堆汙染 (heap pollution)。前面提到應盡量使用 List 優先於陣列,那為何本範例中不用 List ? 在泛型中使用 List,並非所有的 class 都可以這樣使用,為提升效能,像是 ArrayListHashMap 都是建構在陣列之上。在設計上應盡量減少類型轉換的機會,如果有需要支援多種類型,請考慮泛型。
Heap Pollution
https://en.wikipedia.org/wiki/Heap_pollution
轉載請註明原文網址 https://cookieandcoketw.blogspot.com/2020/08/effective-java-29-generic.html

沒有留言:

張貼留言