2017-06-07 28 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