![](/img/trans.png)
[英]Correct way to avoid varargs "method could cause heap pollution from non-reifiable varargs parameter iterators" in Eclipse
[英]java warning: Varargs method could cause heap pollution from non-reifiable varargs parameter
我在 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
參數
假設我知道我在做什么,並假設我很確定不會有堆污染,或者我保證我不會以某種可能導致堆污染的時髦方式調用這個方法,我需要做什么如何抑制此警告消息?
注意:關於 varargs 方法的 stackoverflow 有很多問題,但似乎沒有解決這個特定問題。 事實上,整個interwebz 似乎對這個特定問題的回答相當糟糕。
我在這個問題上看到的所有答案在我看來都不是令人滿意的,所以我想我會嘗試一下。
這是我的看法:
@SafeVarargs
[unchecked] Possible heap pollution from parameterized vararg type Foo
。@SuppressWarnings("varargs")
[varargs] Varargs method could cause heap pollution from non-reifiable varargs parameter bar
。因此,如果我對 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()
可能會barArgs
,從而導致bar()
傳遞地執行它。
因此,我還需要將@SuppressWarnings("varargs")
添加到bar()
以使有關bar()
代碼的警告消失。
事實上,您不應該以這種方式編寫代碼。 考慮以下示例:
import java.util.*;
class Test<T extends Throwable>
{
@SafeVarargs
@SuppressWarnings("varargs")
final void varargsMethod( Collection<T>... varargs )
{
arrayMethod( varargs );
}
void arrayMethod( Collection<T>[] args )
{
Object[] array = args;
array[1] = new Integer(1);
//
//ArrayList<Integer> list = new ArrayList<>();
//list.add(new Integer(1));
//array[1] = list;
}
public static void main(String[] args)
{
ArrayList<Exception> list1 = new ArrayList<>();
ArrayList<Exception> list2 = new ArrayList<>();
(new Test<Exception>()).varargsMethod(list1, list2);
}
}
如果您運行代碼,您將看到一個 ArrayStoreException,因為您將一個 Integer 放入Collection<T>
數組中。
但是,如果替換 array[1] = new Integer(1); 用三個注釋行(即把一個ArrayList<Integer>
放入數組中),由於類型擦除,沒有拋出異常,也沒有出現編譯錯誤。
您想要一個Collection<Exception>
數組,但現在它包含一個ArrayList<Integer>
。 這是非常危險的,因為您不會意識到存在問題。
需要一個額外的(看起來很多余) @SuppressWarnings( "varargs" )
來抑制警告,如下所示:
@SafeVarargs
@SuppressWarnings( "varargs" )
final void varargsMethod( Collection<T>... varargs )
{
arrayMethod( varargs );
}
假設我知道我在做什么
我拒絕假設這一點,因為這似乎非常錯誤。
您在這里遇到的情況是,因為泛型不可具體化,所以您要聲明一個泛型數組,這通常是不受歡迎的。 泛型和數組不能很好地混合,因為數組是協變的( String[]
是一個Object[]
與String
是一個Object
方式相同),而泛型是不變的( List<String>
不是List<Object>
,即使String
是Object
)。
如果你想要一個集合的集合......只需通過一個。 它比混合數組和泛型更安全。
final void varargsMethod(Collection<<Collection<? super T>> collections) { }
這可能解釋了原因。 我剛剛從 Effective Java 2nd Edition, Item 25 復制了它。希望它能有所幫助。
禁止創建通用數組可能很煩人。 例如,這意味着泛型類型通常不可能返回其元素類型的數組(但部分解決方案請參見條款 29)。 這也意味着在將可變參數方法(條目 42)與泛型類型結合使用時,您可能會得到令人困惑的警告。 這是因為每次調用 varargs 方法時,都會創建一個數組來保存 varargs 參數。 如果此數組的元素類型不可具體化,則會收到警告。 除了抑制它們(條款 24)以及避免在 API 中混合泛型和可變參數之外,您對這些警告幾乎無能為力。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.