2017-06-07 30 views
2

我有以下功能:堆污染進行簡單的參數

public static <T> List<T> list(T... xs) { 
    final List<T> lst = new ArrayList<T>(); 
    for (final T x : xs) { 
     lst.add(x); 
    } 

    return lst; 
} 

它的用法很簡單:

List<Integer> ints = list(1, 2, 3, 4) 

編譯器給了我以下警告此列表

「類型安全:潛力通過可變參數的堆污染參數

我試圖找出它的含義,但是我發現的所有解釋都是針對自身參數化的參數的函數,例如,

f(List <T> ... xss)。

雖然我有通用非參數化參數的功能。

請解釋我的功能潛在的問題是什麼,因爲我找不到任何東西。

+1

[相關問答](https://stackoverflow.com/q/12462079/335858) – dasblinkenlight

回答

3

Java中的可變參數是一種合成糖。 T... xsT[] xs相同。因此實際上你有一個參數化參數(數組)的函數。

回到你的問題。讓我們考慮這種情況,當你通過List<String>作爲通用類型的方法。然後你有一組List<String>元素作爲你方法的參數。由此產生了兩個重要問題,並導致代碼中可能存在缺陷。

  1. 數組是協變的,這意味着該compilator將使這個任務:因爲在編譯時數組包含原始List元素和通用擦除Object[] arr = xs
  2. ,不幸的是,在Java中沒有辦法保證,你放入數組中的元素恰好是List<String>。所以如果你把List<Integer>java.lang.ArrayStoreException會在運行時拋出而不是

這一切都會導致您可能會產生堆污染的情況。請參閱下面的例子:

public static <T> List<T> list(T... xs) { 
    final List<T> lst = new ArrayList<T>(); 
    for (final T x : xs) { 
     lst.add(x); 
    } 
    Object[] arr = xs; //arrays are covariant, we can do this 
    arr[0] = Arrays.asList(4); //<--------heap pollution 
    return lst; 
} 
public static void main(String[] args) { 
    List[] arr = { Arrays.asList("one"), Arrays.asList("two"), Arrays.asList("three") }; 
    List<List<String>> l = list(arr); 
    for (List list : arr) { 
     System.out.println(list.get(0)); 
    } 
} 

輸出:

4 
two 
three 

這裏是關於主題一個很好的一個解釋: http://www.angelikalanger.com/GenericsFAQ/FAQSections/ProgrammingIdioms.html#FAQ300

官方Java指南: https://docs.oracle.com/javase/8/docs/technotes/guides/language/non-reifiable-varargs.html

+0

你可以顯示我的使用函數打破這個代碼? – Trismegistos

+0

'Object [] arr = {「one」,「two」,3}; String [] brokenArr =(String [])arr;列表 strings = list(brokenArr);' –

+0

@VasiliyVlasov將'Object []'投射到'String []'拋出'ClassCastException'。 –

2

@ VasiliyVlasov的answer很好地解釋了警告的原因。但在您的問題中,list()方法確實很安全,因爲它不會執行任何不安全的操作。警告只會說有一個「潛在問題」,因爲編譯器無法確定您所調用的方法是否安全地執行。爲了避免這種警告,您可以通過標記@SafeVarargs來保證您方法的安全。有關更多詳細信息,請參閱JavadocJLS