简单参数的堆污染
heap pollution for simple parameter
我有以下功能:
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)
编译器针对此列表给出以下警告
"TypeSafety: potential heap pollution for via varargs parameter
我试图找到它的意思,但我发现的所有解释都是针对本身参数化的参数的函数,例如
f(列表... xss)。
虽然我有通用非参数化参数的功能。
请解释我的函数有什么潜在问题,因为我找不到任何问题。
Java 中的 Varargs 是一种语法糖。 T... xs
与 T[] xs
相同。因此实际上你有一个带有参数化参数(数组)的函数。
回到你的问题。让我们考虑一下这种情况,当您将 List<String>
作为泛型类型传递给方法时。然后你有一个 List<String>
的元素数组作为你的方法的参数。因此出现了两个重要问题,并导致代码中可能存在缺陷。
- 数组是协变的,这意味着编译器将允许这样的赋值:
Object[] arr = xs
- 由于编译时的通用擦除,数组包含原始
List
元素,不幸的是,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
@VasiliyVlasov 的 nicely explains the reason for the warning. But in the context of your question, the list()
method is indeed safe because it doesn't do any unsafe operations. The warning only says there's a "potential problem" because the compiler can't be sure the method you're calling is implemented safely. To avoid the warning, you can vouch for the safety of your method by marking it with @SafeVarargs
. See the Javadoc and the JLS 了解更多详情。
我有以下功能:
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)
编译器针对此列表给出以下警告
"TypeSafety: potential heap pollution for via varargs parameter
我试图找到它的意思,但我发现的所有解释都是针对本身参数化的参数的函数,例如
f(列表
虽然我有通用非参数化参数的功能。
请解释我的函数有什么潜在问题,因为我找不到任何问题。
Java 中的 Varargs 是一种语法糖。 T... xs
与 T[] xs
相同。因此实际上你有一个带有参数化参数(数组)的函数。
回到你的问题。让我们考虑一下这种情况,当您将 List<String>
作为泛型类型传递给方法时。然后你有一个 List<String>
的元素数组作为你的方法的参数。因此出现了两个重要问题,并导致代码中可能存在缺陷。
- 数组是协变的,这意味着编译器将允许这样的赋值:
Object[] arr = xs
- 由于编译时的通用擦除,数组包含原始
List
元素,不幸的是,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
@VasiliyVlasov 的 list()
method is indeed safe because it doesn't do any unsafe operations. The warning only says there's a "potential problem" because the compiler can't be sure the method you're calling is implemented safely. To avoid the warning, you can vouch for the safety of your method by marking it with @SafeVarargs
. See the Javadoc and the JLS 了解更多详情。