当前位置: 首页 > 知识库问答 >
问题:

枚举的“通过varargs参数造成的潜在堆污染”...为什么?

燕志学
2023-03-14

此问题特定于将varargs与泛型枚举 一起使用:

为什么我会得到这个警告类型安全:通过varargs参数元素潜在的堆污染如果我像下面这样定义方法:

<E extends Enum<E>> void someMethod(E... elements)

与此相反的是:

<E extends Enum<E>> void someMethod(E[] elements)

因此,在声明方法@safevarargs之前,我应该注意什么?

此问题类似于以下关于集合的问题 ... ,但这些答案中显示的方案似乎不适用于枚举 ... :

    null
    null

这就是我试图污染堆的原因,但是每次错误的尝试都会导致java.lang.ArrayStoreException而不是污染数组。

我使用的是Eclipse4.6.0和Java JDK8U74。

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

共有1个答案

穆鸿卓
2023-03-14

varargs方法有一个警告,因为varargs方法可能导致在调用站点创建隐式数组,而接受数组参数的版本不会。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 7在使用泛型类型的varargs时会出现这种情况; 但我的问题是.. 当Eclipse说“它的使用可能会潜在地污染堆”时,它到底是什么意思? 而且 新的注释如何防止这种情况发生?

  • 问题内容: 我知道在Java 7中使用带有泛型类型的varargs时会发生这种情况。 但是我的问题是.. Eclipse说“使用它可能会污染堆”时,这到底是什么意思? 和 新注释如何防止这种情况? 问题答案: 堆污染是一个技术术语。它引用的引用类型不是其指向的对象的超类型。 这可能会导致“无法解释” 。 @SafeVarargs完全不能阻止这一点。但是,有些方法证明不会污染堆,编译器无法证明这一点

  • 问题内容: 我在JDK 1.8上将IntelliJ IDEA与javac一起使用。我有以下代码: IntelliJ IDEA不会在上面的代码中突出显示任何内容作为警告。但是,在编译时,以下行将显示在“消息”视图的“生成”选项卡中: 警告:(L,C)java:Varargs方法可能会导致不可修改的varargs参数varargs造成堆污染 注意#1:我已经指定了。 注意#2:指向作为参数传递给 假设

  • 描述 HTTP 参数污染,或者 HPP,在网站接受用户输入,将其用于生成发往其它系统的 HTTP 请求,并且不校验用户输出的时候发生。它以两种方式产生,通过服务器(后端)或者通过客户端。 在 StackExchange 上,SilverlightFox 提供了一个 HPP 服务端攻击的不错的例子。假设我们拥有以下站点:https://www.example.com/transferMoney.ph

  • 我听到一些人建议在C++中使用枚举类,因为它们的类型安全。 但这到底意味着什么呢?

  • 枚举具有名为'hash value'的属性,该属性是枚举内的索引。