"Potential heap pollution through the varargs parameter" for Enum <E> ... why?
This question is specific to using varargs with generic-fied Enum<E> s:
Why do I get this warning Type safety: Potential heap pollution via varargs parameter elements if I define a method like this:
<E extends Enum<E>> void someMethod(E... elements) In contrast to this:
<E extends Enum<E>> void someMethod(E[] elements) Accordingly, what should I look for before declaring the @SafeVarargs method?
Related questions
This question is similar to these questions regarding Collection<T>... , but the scripts shown in these answers do not seem to apply to Enum<E>... :
- Potential heap pollution through the varargs parameter
- Security Type: potential heap pollution through varargs parameter subparameters
- Potential heap pollution through the varargs parameter
- Eclipse different behavior for the “Unchecked” warning due to “potential heap pollution through the varargs parameter”. How to fix?
In this backward question, the question is why there are no warnings:
Code example
This is what I tried to pollute the heap, but every failed attempt results in a java.lang.ArrayStoreException , not a polluted array.
I am using Eclipse 4.6.0 and Java JDK 8u74.
public static void main(String[] args) { Foo[] x = { Foo.A }; someMethod(x); Foo y = x[0]; // How does one get a ClassCastException here? } private static enum Foo { A, B, C, } private static enum Bar { X, Y, Z, } // This produces a "Type safety" warning on 'elements' private static <E extends Enum<E>> void someMethod(E... elements) { Object[] objects = elements; // Test case 1: This line throws java.lang.ArrayStoreException objects[0] = ""; // Test case 2: Program terminates without errors objects[0] = Foo.A; // Test case 3: This line throws java.lang.ArrayStoreException objects[0] = Bar.X; } There is a warning for the varargs method, because the varargs methods can cause the array to be created implicitly on the calling site, while the version that accepts the array parameter does not work. The way varargs works is that it forces the compiler to create an array on the call site, filled with variable arguments, which is then passed to the method as one array parameter. The parameter would be of type E[] , so the created array must be E[] .
First, in the call site in your example, you don’t use the functionality of the variables at all. You pass an array of variable arguments directly. So in this case there is no implicit array creation.
Even if you used the functionality of variable arguments, for example. with someMethod(Foo.A); , creating an implicit array will create an array with a return type, i.e. the type of the variable argument is known on the call site as Foo , which is the concrete type known at compile time, so creating an array is good.
The only problem is that the type of the variable argument at the call site is also a typical type or type of parameter. For example, something like:
public static <E extends Enum<E>> void foo(E obj) { someMethod(obj); } Then the compiler will need to create an array of this type or type parameter (he needs to create E[] ), but as you know, creating a shared array in Java is not allowed. Instead, it will create an array with the type of the component that is erasing the generic type (in this example, it will be Enum ), so it will pass an array of the wrong type (in this example, the passed array must be E[] , but the actual execution class of the array will be Enum[] which is not a subtype of E[] ).
This potential incorrect array type is not always a problem. In most cases, the varargs method will simply iterate over the array and get elements from it. In this case, the runtime class of the array does not matter; all that matters is that the elements are of type E (which they are). If so, you can declare your @SafeVarargs method. However, if your method actually uses the runtime class of the passed array (for example, if you return the varargs array as type E[] or use something like Arrays.copyOf() to create an array with the same runtime class), then the wrong class array runtime will cause problems and you cannot use @SafeVarargs .
Your example is a bit strange because, well, you don’t even use the fact that the elements are of type E , not to mention the array E[] . That way you can use @SafeVarargs , and not only that, you can just declare the array as receiving Object[] in the first place:
private static void someMethod(Object... objects)