195

@SafeVarargs最近、Javaアノテーションに出くわしました。Javaの可変個引数関数を安全でないものにするものをグーグルで検索すると、かなり混乱しました(ヒープ中毒?消去された型?)ので、いくつか知りたいことがあります。

  1. 可変個引数Java関数をある@SafeVarargs意味で危険なものにするのは何ですか(詳細な例の形で説明することが望ましい)?

  2. なぜこの注釈はプログラマーの裁量に任されているのですか?これはコンパイラがチェックできるはずのことではありませんか?

  3. 彼の機能が実際にvarags安全であることを保証するために遵守しなければならないいくつかの標準はありますか?そうでない場合、それを確実にするためのベストプラクティスは何ですか?

4

2 に答える 2

271

1) ジェネリックと可変引数に関する特定の問題について、インターネットと StackOverflow に多くの例があります。基本的に、型パラメータ型の可変数の引数がある場合です。

<T> void foo(T... args);

Java では、varargs はコンパイル時に単純な「書き直し」を受けるシンタックス シュガーです。type の varargs パラメータは typeX...のパラメータに変換されますX[]。この varargs メソッドが呼び出されるたびに、コンパイラは varargs パラメータに含まれるすべての「可変引数」を収集し、 と同じように配列を作成しますnew X[] { ...(arguments go here)... }

これは、varargs 型が のように具体的である場合にうまく機能しますString...。のような型変数の場合、 がその呼び出しの具象型であることがわかってT...いる場合にも機能します。Tたとえば、上記のメソッドが class の一部でありFoo<T>、参照がある場合、コードのその時点であることがわかっているためFoo<String>、それを呼び出すことは問題ありません。fooTString

Tただし、の「値」が別の型パラメーターの場合は機能しません。Java では、型パラメータ コンポーネント型 ( new T[] { ... }) の配列を作成することはできません。そのため、Java は代わりにnew Object[] { ... }(ここObjectに の上限をT示します。上限が何か異なる場合は、代わりにObject) を使用し、コンパイラの警告を表示します。

new Object[]では、代わりに何かを作成することの何が問題なのnew T[]ですか? Java の配列は、実行時にコンポーネントの型を認識します。したがって、渡された配列オブジェクトは、実行時に間違ったコンポーネント タイプになります。

おそらく最も一般的な varargs の使用法では、単純に要素を反復処理するため、これは問題ありません (配列の実行時の型は気にしません)。したがって、これは安全です。

@SafeVarargs
final <T> void foo(T... args) {
    for (T x : args) {
        // do stuff with x
    }
}

ただし、渡された配列のランタイム コンポーネント タイプに依存するものは安全ではありません。以下は、安全でなくクラッシュする単純な例です。

class UnSafeVarargs
{
  static <T> T[] asArray(T... args) {
    return args;
  }

  static <T> T[] arrayOfTwo(T a, T b) {
    return asArray(a, b);
  }

  public static void main(String[] args) {
    String[] bar = arrayOfTwo("hi", "mom");
  }
}

ここでの問題は、 をとして返すためにargs、の型に依存していることです。しかし実際には、実行時の引数の型は のインスタンスではありません。T[]T[]T[]

3) メソッドに型の引数がある場合T...(T は任意の型パラメーター)、次のようになります。

  • 安全: メソッドが配列の要素がのインスタンスであるという事実のみに依存している場合T
  • 安全でない: 配列がのインスタンスであるという事実に依存する場合T[]

配列の実行時型に依存するものには、 type として返す、 typeT[]のパラメーターに引数として渡す、をT[]使用して配列型を取得する、配列.getClass()の実行時型に依存するメソッドに渡す、などがList.toArray()あります。Arrays.copyOf()など

2) 上記の区別は複雑すぎて、自動的に簡単に区別することはできません。

于 2013-01-10T06:43:43.480 に答える