アイテムジェニーリックと一緒に可変パラメータを使用する場合は慎重にしてください。
可変パラメータは、クライアントがメソッドに渡す買収数を制御することを可能にするが、実施形態には脆弱性がある. 可変パラメータメソッドが呼び出されると、可変パラメータを含む配列が自動的に生成されます.そのため、内部に隠すべきこの配列をクライアントに暴露する問題が発生しました. の結果、varargsパラメータにJENICまたはパラメトリックタイプが含まれている場合、識別しにくいコンパイル警告が表示されます.非実体化タイプ
非実体化タイプは、コンパイルタイプよりも実行時に少ないタイプ関連情報を含む. ほとんどのジュネーブとパラメトリックタイプは実体化されていません. メソッドを宣言すると、varargsパラメータを非実体化タイプで宣言すると、コンパイラは警告します. 可変パラメータメソッドを呼び出すと、varargsパラメータが非実体化タイプと推定されると、その呼び出しにも警告が表示されます. パラメトリックタイプの変数はタイプの異なるオブジェクトを参照し、hip汚染を生じる.ジェニーリックとvarargsを混合して使用すると、タイプのセキュリティが破壊されます。
public class Item32 {
static void dangerous(List<String>... stringLists) {
List<Integer> intList = List.of(42);
Object[] objects = stringLists;
objects[0] = intList;
String s = stringLists[0].get(0);
}
}
コンパイラは、見えない変換を自動的に行います.したがって,この方法では形状を変換する場所でパラメータを呼び出すとClassCastExceptionが放出される. のようなタイプのセキュリティが破壊されるため、generic varargsアレイパラメータに値を格納することは安全ではありません. JENERIC配列の直接記述は許可されていませんが、JENERIC varargsパラメータを受信する方法を宣言できる理由は次のとおりです.言語設計者は、パラメトリックタイプのvarargsパラメータを受け入れる方法が実際の作業で非常に有用であるため、この矛盾を受け入れることを決定した. Javaライブラリでは、タイプが安全な多くの方法が提供されています. ex. Arrays.asList(T... a)
, Collections.addAll(Collection<? super T> c, T... elements)
, EnumSet.of(E first, E... rest)
@SafeVarargs
java 7の前に、JENERIC可変パラメータメソッドの作成者が発呼者で発した警告を処理する方法はありません.ユーザーは、これらの警告を任意の場所に配置するか、警告を非表示にするために呼び出された場所に@SuppressWarnings(「unchecked」)コメントを追加する必要があります. java 7は@SafeValargsプレゼンテーションを追加し、JENARIC可変パラメータメソッドの作成者がクライアントからの警告を隠すことができるようにした. @SafeValargsプレゼンテーションは、メソッド作成者がメソッドタイプのセキュリティを保証するデバイスです.コンパイラは、この約束を信じて、この方法が安全ではない可能性があることを警告しません. メソッドが安全であることが確認されていない場合は、@SafeValargsコメントを付けてはいけません.可変パラメータメソッドを呼び出すと、varargsパラメータを含むgeneric配列が作成されます. の場合、メソッドがその配列に何も格納されず(これらのパラメータを上書きしない)、配列内の参照が外部に露出しない場合(信頼できないコードが配列にアクセスできない場合)、タイプは安全です. 、すなわち、varargsパラメータ配列が呼び出し元の方法のみでパラメータを純粋に伝達する場合、この方法は安全である.独自のJENICパラメータ配列の参照を表示-安全ではありません。
public class Item32 {
static <T> T[] toArray(T... args) {
return args;
}
}
このメソッドが返す配列タイプは、このメソッドにパラメータを渡すコンパイル時間によって決まります.この場合、コンパイラは十分な情報を得ることができないため、エラーのタイプを判断する可能性があります. が独自のvarargsパラメータ配列を返すと、hip汚染はメソッドを呼び出す側のcallスタックに移行する.Jeneric varargsパラメータ配列に他の方法でアクセスできる場合は、安全ではありません。
しかし、2つの例外がある.
の最初の方法は、@SafeValargsで別の正しいvarargsメソッドに転送するのが安全です.第
第2に、この配列の内容のいくつかの関数を呼び出し(varargsを受け入れない)のみに渡す従来の方法も安全である.Jenericvarargsパラメータを安全に使用する方法
public class Item32 {
@SafeVarargs
static <T> List<T> flatten(List<? extends T>... lists) {
List<T> result = new ArrayList<>();
for (List<? extends T> list : lists) {
result.addAll(list);
}
return result;
}
}
@SafeValargsプレゼンテーションをいつ使用するかを決定するルールは簡単です. パラメータ化タイプのvarargsパラメータを受け入れるすべての方法に@SafeValargsを加えるとよい. つまり、決して安全でないvarargsメソッドを記述してはいけない.次の2つの条件を満たすZenirick varargs法は安全である。
varargsパラメータ配列には何も格納されません. は、その配列(またはコピー)を信頼できないコードに露出しない.@SafeValargsプレゼンテーションは、再定義できないメソッドにのみインストールする必要があります.再定義の方法も安全を保証できないからです.
Java 8では、このプレゼンテーションは静的メソッドとfinalインスタンスメソッドにのみ貼り付けられ、java 9からプライベートインスタンスメソッドでも使用できます.
リストを使用してJenericvarargsパラメータを置換する例-タイプセキュリティ。
public class Item32 {
static <T> List<T> flatten(List<List<? extends T>> lists) {
List<T> result = new ArrayList<>();
for (List<? extends T> list : lists) {
result.addAll(list);
}
return result;
}
}
@SafeValargsプレゼンテーションは唯一の正解ではありません. の例では、上記の方法のように配列varargsパラメータをListパラメータに変更してもよい.List.of
class Item32 {
List<T> audience = flatten(List.of(friends, romans, countrymen));
}
静的ファクトリメソッドのリスト.ofを利用すると,上記のように任意の因数をスキップすることができる. List.ofに@SafeValargsコメントが付いているので、これは可能です. この方法の利点は、コンパイラがこの方法のタイプのセキュリティを検証できることである. の欠点であれば、クライアントコードが少し汚くなり、速度が少し遅くなる可能性があります. さらに、この方式は、上述したtoArrayのようにvarargsメソッドを安全に記述することが不可能な場合にも使用することができる. toArrayのListバージョンがListですofはjavaライブラリの観点から提供され、私たちが自分で書く必要はありません. を使用すると、結果コードは並べ替えられず、Genericのみが使用されるため、タイプは安全です.コアの整理
可変生命とジェニーンリックはあまり合わない.可変パラメータ機能は配列を露呈しているため,抽象化が不十分で,配列はJENICのタイプ規則とは異なる. Jenericvarargsパラメータタイプは安全ではありませんが、許可されています. メソッドでJENARIC(またはパラメトリック)varargsパラメータを使用する場合は、このメソッドタイプが安全であることを確認し、@SafeValargsコメントを付けて使用の不便を回避します.