Enum<E>
s:
Type safety: Potential heap pollution via varargs parameter elements
:
<E extends Enum<E>> void someMethod(E... elements)
与此相反:
<E extends Enum<E>> void someMethod(E[] elements)
因此,在声明方法之前我应该注意什么
@SafeVarargs
?
类似问题
Collection<T>...
的问题类似,但这些答案中显示的场景似乎不适用于
Enum<E>...
:
java.lang.ArrayStoreException
而不是污染的数组。
我正在使用 Eclipse 4.6.0
和 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;
}
E[]
,因此创建的数组应该是
E[]
。首先,在示例的调用站点中,您根本没有使用变量参数功能。您直接传递变量参数数组。所以在这种情况下没有隐式数组创建。
即使您使用了变量参数功能,例如使用
someMethod(Foo.A);
,隐式数组创建将创建一个具有可具体化类型的数组,即,在调用站点已知变量参数类型为
Foo
,这是编译时已知的具体类型,因此数组创建是很好。仅当调用站点的变量参数类型也是泛型类型或类型参数时才会出现问题。例如,类似:
public static <E extends Enum<E>> void foo(E obj) {
someMethod(obj);
}
然后编译器需要创建一个该泛型类型或类型参数的数组(它需要创建一个
E[]
),但如您所知,Java 中不允许创建泛型数组。相反,它会创建一个数组,其组件类型是泛型类型的擦除(在本例中它将是
Enum
),因此它将传递错误类型的数组(在本例中,传递的数组应该是E[]
,但数组的实际运行时类将是 Enum[]
,它不是 E[]
的子类型)。这种可能错误的数组类型并不总是一个问题。大多数时候,可变参数方法将简单地迭代数组并从中获取元素。在这种情况下,数组的运行时类是无关紧要的;重要的是元素是 E
类型(它们确实是)。如果是这种情况,您可以声明您的方法
@SafeVarargs
。但是,如果您的方法实际上使用传递数组的运行时类(例如,如果您以 E[]
类型返回 varargs 数组,或者使用 Arrays.copyOf()
之类的内容创建具有相同运行时类的数组),那么数组的错误运行时类会导致问题,并且您无法使用@SafeVarargs
。你的例子有点奇怪,因为,你甚至没有使用元素类型为 E
的事实,更不用说数组是
E[]
的事实了。因此,您可以使用 @SafeVarargs
,不仅如此,您还可以简单地将数组声明为首先采用 Object[]
:private static void someMethod(Object... objects)