effective java 第32條 謹慎並用泛型和可變參數

1.可變參數的作用在於讓客戶端能夠將可變數量的參數傳給方法,但這是個技術露底:當調用一個可變參數方法時,會創建一個對象數組Object[]用來存放可變參數;這個數組應該是一個實現細節,他是可見的。因此,當可變參數有泛型或者參數化類型時,編譯警告信息就會產混亂。

2.當一個參數化類型的變量指向一個不是該類型的對象時,會產生堆污染(heap pullution)。它導致編輯器的自動生成轉換失敗,破壞了泛型系統的基本保證。

3.java7中,增加了@SafeVarargs註解,它讓帶泛型vararg參數的方法的設計者能夠自動禁止客戶端的警告。本質上@SafeVarargs註解是通過方法的設計者做出承諾,聲明這類型是安全的。所以不要隨意使用@SafeVarargs對方法進行註解,除非它是真正安全的。

 

代碼示例:

package effectivejava;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;

/**
 * 謹慎並用泛型可變參數:
 * 1.可變參數的作用在於讓客戶端能夠將可變數量的參數傳給方法,但這是個技術露底:當調用一個可變參數方法時,會創建一個對象數組Object[]用來存放可變參數;這個數組應該是一個實現細節,他是可見的。因此,當可變參數有泛型或者參數化類型時,編譯警告信息就會產混亂。2.當一個參數化類型的變量指向一個不是該類型的對象時,會產生堆污染(heap pullution)。它導致編輯器的自動生成轉換失敗,破壞了泛型系統的基本保證。
3.java7中,增加了@SafeVarargs註解,它讓帶泛型vararg參數的方法的設計者能夠自動禁止客戶端的警告。本質上@SafeVarargs註解是通過方法的設計者做出承諾,聲明這類型是安全的。所以不要隨意使用@SafeVarargs對方法進行註解,除非它是真正安全的。
 * 
 * @author wangcaiyan[[email protected]]
 *
 */
public class VarargT {
    
    public static void main(String[] args) {
        // java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String;
        //允許另一個方法訪問一個泛型可變參數數組是不安全的。
//        String[] arr = pickTwo("Good", "Fast", "Cheap");
        List<String> strList = new ArrayList<>();
        strList.add("work");
        dangerous(strList);
    }
    
    //unsafe
    //當調用一個可變參數方法時,會創建一個對象數組Object[]用來存放可變參數
    static <T> T[] toArray(T... args) {
        return args;
    }
    
    static <T> T[] pickTwo(T a , T b, T c) {
        switch (ThreadLocalRandom.current().nextInt(3)) {
        case 0:
            return toArray(a, b);
        case 1:
            return toArray(a, c);
        case 2:
            return toArray(c, b);
        }
        throw new AssertionError();
    }
    
    //當調用一個可變參數方法時,會創建一個對象數組Object[]用來存放可變參數
    static void dangerous(List<String>... stringLists) {
        List<Integer> intList = new ArrayList<>();
        intList.add(42);
        Object[] objects = stringLists;
        objects[0] = intList; // heap pullution:將List<Integer>放入List<String>
        String s = stringLists[0].get(0); // classCastException:java.lang.Integer cannot be cast to java.lang.String
        System.out.println(s);
    }
    
    

}
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章