これは、Java 7でジェネリック型のvarargsを使用するときに発生することを理解しています。
しかし、私の質問です。
「使用するとヒープが汚染される可能性がある」とEclipseが正確に意味するのは何ですか?
そして
新しい@SafeVarargs
アノテーションはどのようにこれを防ぎますか?
Possible heap pollution from parameterized vararg type
これは、Java 7でジェネリック型のvarargsを使用するときに発生することを理解しています。
しかし、私の質問です。
「使用するとヒープが汚染される可能性がある」とEclipseが正確に意味するのは何ですか?
そして
新しい@SafeVarargs
アノテーションはどのようにこれを防ぎますか?
Possible heap pollution from parameterized vararg type
回答:
ヒープ汚染は専門用語です。参照先のオブジェクトのスーパータイプではないタイプを持つ参照を参照しています。
List<A> listOfAs = new ArrayList<>();
List<B> listOfBs = (List<B>)(Object)listOfAs; // points to a list of As
これは、「説明できない」につながる可能性がありClassCastException
ます。
// if the heap never gets polluted, this should never throw a CCE
B b = listOfBs.get(0);
@SafeVarargs
これをまったく防止しません。ただし、ヒープを汚染しないと思われるメソッドがあり、コンパイラはそれを証明できません。以前は、そのようなAPIの呼び出し元は、完全に無意味な警告を受け取りましたが、すべての呼び出しサイトで抑制する必要がありました。これで、API作成者は宣言サイトで一度抑制できます。
ただし、メソッドが実際に安全でない場合、ユーザーに警告は表示されなくなります。
宣言するとき
public static <T> void foo(List<T>... bar)
コンパイラはそれを
public static <T> void foo(List<T>[] bar)
それから
public static void foo(List[] bar)
次に、誤った値をリストに誤って割り当て、コンパイラがエラーをトリガーしないという危険が生じます。例えば、場合T
されString
、その後、次のコードは、エラーなしでコンパイルされますが、実行時に失敗します。
// First, strip away the array type (arrays allow this kind of upcasting)
Object[] objectArray = bar;
// Next, insert an element with an incorrect type into the array
objectArray[0] = Arrays.asList(new Integer(42));
// Finally, try accessing the original array. A runtime error will occur
// (ClassCastException due to a casting from Integer to String)
T firstElement = bar[0].get(0);
メソッドを見直して、そのような脆弱性が含まれていないことを確認した場合は、注釈を付けて@SafeVarargs
警告を抑制できます。インターフェイスには、を使用します@SuppressWarnings("unchecked")
。
このエラーメッセージが表示された場合:
Varargsメソッドは、再構成不可能なvarargsパラメーターからのヒープ汚染を引き起こす可能性があります
そして、あなたはあなたの使用が安全であると確信しているので、@SuppressWarnings("varargs")
代わりに使用するべきです。@SafeVarargsはこのメソッドの適切な注釈ですか?を参照してください。この2番目の種類のエラーについては、https://stackoverflow.com/a/14252221/14731を参照してください。
参照:
Object[]
。にキャストしない限り、問題ないように思えObject[]
ます。
static <T> void bar(T...args) { ((Object[])args)[0] = "a"; }
。次にを呼び出しますbar(Arrays.asList(1,2));
。
Object[]
コンパイラが警告をトリガーするのはなぜですか?結局、これをコンパイル時にかなり簡単にチェックできるはずです(同様のシグネチャを持つ別の関数に渡さない場合、他の関数は警告をトリガーするはずです)。これが本当に警告の核心だとは信じていません(「キャストしなくても大丈夫です」)。それでも、私はそれでも問題ありません。
bar(Integer...args)
。では、この警告の意味は何でしょうか。
@SafeVarargs
それが起こるのを防ぐわけではありませんが、それを使用するコードをコンパイルするとき、コンパイラーはより厳格であることを義務付けます。
http://docs.oracle.com/javase/7/docs/api/java/lang/SafeVarargs.htmlでこれについてさらに詳しく説明しています。
ヒープ汚染とはClassCastException
、ジェネリックインターフェイスで操作を行うときに、宣言されたものとは別のタイプが含まれている場合です。
varargsを使用Object[]
すると、引数を保持するためのが作成される可能性があります。
エスケープ分析により、JITはこの配列の作成を最適化できます。(私がそれを見つけた数回のうちの1つはそうすることを発見しました)最適化で削除されることは保証されていませんが、メモリプロファイラーに問題がない限り、心配する必要はありません。
AFAIK @SafeVarargs
はコンパイラによる警告を抑制し、JITの動作を変更しません。
@SafeVarargs
。
その理由は、varargsがパラメーター化されていないオブジェクト配列で呼び出されるオプションを提供するためです。したがって、タイプがList <A> ...の場合、List []非可変引数タイプで呼び出すこともできます。
次に例を示します。
public static void testCode(){
List[] b = new List[1];
test(b);
}
@SafeVarargs
public static void test(List<A>... a){
}
ご覧のとおり、List [] bには任意のタイプのコンシューマーを含めることができますが、このコードはコンパイルされます。varargsを使用する場合は問題ありませんが、型の消去後にメソッド定義を使用する場合(void test(List []))、コンパイラーはテンプレートパラメーターの型をチェックしません。@SafeVarargsはこの警告を抑制します。