这个问题特定于将varargs与泛型Enum<E>一起使用:

如果我定义如下方法,为什么会得到这个警告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>...:
  • Potential heap pollution via varargs parameter
  • Type safety: Potential heap pollution via varargs parameter subtrees
  • Potential heap pollution via varargs parameter
  • Eclipse different behaviour for "Unchecked" warning due to "Potential heap pollution via varargs parameter". How to fix?

  • 这个问题的反面是为什么没有警告的问题:
  • Why doesn't the following method produce potential heap pollution?

  • 样例代码

    这就是我试图污染堆的方法,但是每次错误尝试都会导致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;
    }
    

    最佳答案

    对于varargs方法有一个警告,因为varargs方法可能会在调用站点上导致隐式创建数组,而采用array参数的版本则不会。 varargs的工作方式是,它使编译器在调用站点创建一个填充有变量参数的数组,然后将其作为单个数组参数传递给该方法。该参数的类型为E[],因此创建的数组应为E[]

    首先,在示例的调用站点中,您根本没有使用变量参数功能。您正在直接传递可变参数数组。因此,在这种情况下不会隐式创建数组。

    即使您使用了可变参数功能,例如使用someMethod(Foo.A);时,隐式数组创建将创建具有可更改类型的数组,即在调用站点处将变量参数类型称为Foo,这是在编译时已知的具体类型,因此数组创建很好。

    问题仅在调用站点上的变量参数类型也是通用类型或类型参数的情况下。例如,类似:

    public static <E extends Enum<E>> void foo(E obj) {
        someMethod(obj);
    }
    

    然后,编译器将需要创建此通用类型或类型参数的数组(它需要创建E[]),但是您知道Java中不允许创建通用数组。相反,它将创建一个数组,其组件类型为通用类型的擦除(在此示例中为Enum),因此它将传递错误类型的数组(在此示例中,传递的数组应为E[],但是数组的实际运行时类将是Enum[],它不是E[]的子类型。

    这种潜在的错误类型的数组并不总是一个问题。大多数时候,varargs方法将简单地遍历数组并从中取出元素。在这种情况下,数组的运行时类无关紧要;重要的是元素是E类型(实际上是)。在这种情况下,您可以声明方法@SafeVarargs。但是,如果您的方法实际上使用了传递的数组的运行时类(例如,如果您将varargs数组返回为E[]类型,或者您使用了类似Arrays.copyOf()的东西来创建具有相同运行时类的数组),则错误的运行时类数组的数组将导致问题,您不能使用@SafeVarargs

    您的示例有些奇怪,因为,您甚至没有使用元素为E类型的事实,更不用说数组为E[]的事实了。因此,您不仅可以使用@SafeVarargs,还可以简单地将数组声明为采用Object[]:
    private static void someMethod(Object... objects)
    

    关于java - Enum <E>的"Potential heap pollution via varargs parameter"...为什么?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/38781226/

    10-10 13:48