Enum 的“通过可变参数参数可能造成堆污染”...为什么?<E>

问题描述 投票:0回答:1
这个问题特定于将可变参数与泛型一起使用

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>...

    通过可变参数参数造成的潜在堆污染
  • 类型安全:通过可变参数参数子树造成潜在的堆污染
  • 通过可变参数参数造成的潜在堆污染
  • 由于“可变参数参数造成潜在堆污染”,Eclipse 出现“未检查”警告的不同行为。怎么解决?
  • 这个问题的反面质疑为什么没有警告:

    为什么下面的方法不会产生潜在的堆污染?
  • 示例代码

这就是我试图污染堆的方法,但每次错误的尝试都会导致

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; }


java enums variadic-functions
1个回答
21
投票
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)

© www.soinside.com 2019 - 2024. All rights reserved.