小编典典

Java警告:Varargs方法可能会导致来自不可修改的varargs参数的堆污染

java

我在JDK 1.8上将IntelliJ IDEA与javac一起使用。我有以下代码:

class Test<T extends Throwable>
{
    @SafeVarargs
    final void varargsMethod( Collection<T>... varargs )
    {
        arrayMethod( varargs );
    }

    void arrayMethod( Collection<T>[] args )
    {
    }
}

IntelliJ IDEA不会在上面的代码中突出显示任何内容作为警告。但是,在编译时,以下行将显示在“消息”视图的“生成”选项卡中:

警告:(L,C)java:Varargs方法可能会导致不可修改的varargs参数varargs造成堆污染

注意#1:我已经指定了@SafeVarargs

注意#2:Warning:(L,C)指向varargs作为参数传递给arrayMethod()

假设我知道自己在做什么,并且假设我非常确定不会出现堆污染,或者我保证不会以某种时髦的方式调用此方法,这可能会导致堆污染,
那么我需要做些什么?禁止显示此警告消息?

注意:
关于varargs方法,有很多关于问题,但是似乎没有一个问题可以解决此特定问题。实际上,整个interwebz在回答这个特定问题方面似乎很差。


阅读 1039

收藏
2020-11-23

共1个答案

小编典典

在这个问题上,我所看到的答案都没有一个令人满意,因此,我认为自己会对此持怀疑态度。

这是我的看法:

  1. @SafeVarargs

    • 是解决警告的方法:[unchecked] Possible heap pollution from parameterized vararg type Foo
    • 是方法 约定的 一部分,因此注释为何具有运行时保留
    • 向方法的调用者保证,该方法不会使用泛型varargs参数弄乱堆。
    • @SuppressWarnings("varargs")

    • 是解决警告的方法:[varargs] Varargs method could cause heap pollution from non-reifiable varargs parameter bar

    • 解决方法代码 发生的问题,而不是方法合同上的问题,因此注释为何仅保留源代码
    • 告诉编译器无需担心方法代码 调用的被调用方方法会 使用由不可修改的varargs参数产生的数组将堆弄乱。

因此,如果我对OP的原始代码进行以下简单修改:

class Foo {
    static <T> void bar(final T... barArgs) {
        baz(barArgs);
    }
    static <T> void baz(final T[] bazArgs) { }
}

$ javac -Xlint:all Foo.java使用Java 9.0.1编译器的输出为:

Foo.java:2: warning: [unchecked] Possible heap pollution from parameterized vararg type T
    static <T> void bar(final T... barArgs) {
                                   ^
  where T is a type-variable:
    T extends Object declared in method <T>bar(T...)
1 warning

我可以通过将标记bar()为来消除该警告@SafeVarargs。这既使得警告消失 ,并
通过增加可变参数安全的方法合同,确保任何人谁通话bar将不必抑制任何可变参数的警告。

但是,这也使Java编译器更加仔细地查看了方法代码本身-
我想是为了验证一些简单的情况,在这些情况下bar()可能违反了我刚刚订立的合同@SafeVarargs。而且它看到bar()所调用baz()传递barArgs和数据,因为baz()需要一个Object[]因类型擦除,baz()会搞乱了堆,从而导致bar()以传递地做到这一点。

因此,我还需要添加@SuppressWarnings("varargs")bar()以使有关bar()的代码的警告消失。

2020-11-23