当前位置: 首页 > 面试题库 >

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

李博达
2023-03-14
问题内容

我在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在回答这个特定问题方面似乎很差。


问题答案:

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

这是我的看法:

  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()的代码的警告消失。



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

  • 我知道Java 7在使用泛型类型的varargs时会出现这种情况; 但我的问题是.. 当Eclipse说“它的使用可能会潜在地污染堆”时,它到底是什么意思? 而且 新的注释如何防止这种情况发生?

  • 我目前正在设置IntelliJ Inspection Profile,以便它可以在编辑器中指出潜在的问题。但我并没有找到一种方法来指出javac警告“最后一个参数的参数类型不精确的varargs方法的非varargs调用;”。 考虑下面的片段: 在Eclipse中,方法调用,带有下划线(带有一条锯齿状的黄线),但在IntelliJ中,这似乎不会被检查发现。不过,当我在IntelliJ中编译文件时,

  • 但是,如果Terminal中没有提供,我不知道如何(或者是否能够)为其设置默认值。像这样简单的东西不起作用。这里的一个解决方案是根据的内容或大小在函数中设置变量。但我不知道有没有更好的办法做到这一点。 因此,我正在寻找一种方法来使用来自终端的参数调用一个函数,其中需要一个数字(在本例中为2),而其余的是可选的,并设置为默认值。

  • 问题内容: 考虑方法声明: 该Object …参数只是对Objects 数组的引用。有没有办法在引用实际Object数组时使用此方法?如果我将Object数组传递给…参数-结果参数值将是一个二维数组-因为an Object[]本身就是an Object: 因此,数组的第一个组件(String.format方法中使用了哪个)将是一个数组,他将生成: 然后由于数组大小为1而发生错误。 该大胆的顺序是真

  • 问题内容: 编码我来检查Java的vararg性能。 我编写以下测试代码: 在我的机器上,平均输出为: 似乎将变量传递给方法是免费的!好! 但是使用varags慢60倍!为什么呢 一种解释可能是程序必须在堆上创建数组,而时间是由GC花费的。但是对于更少的循环,我仍然得到输出: 什么花费了这些额外的时间,反正编译器拥有将其解决为fix变量调用的所有信息… 这不是我打算为此进行优化的意图,但是我发现这