web-dev-qa-db-ja.com

コンストラクター参照-ジェネリック配列が作成されたときに警告なし

Javaでは、ジェネリック型の配列を直接作成することはできません。

Test<String>[] t1 = new Test<String>[10]; // Compile-time error

ただし、これはrawタイプを使用して行うことができます。

Test<String>[] t2 = new Test[10]; // Compile warning "unchecked"

Java 8では、コンストラクタ参照を使用することも可能です。

interface ArrayCreator<T> {
    T create(int n);
}

ArrayCreator<Test<String>[]> ac = Test[]::new; // No warning
Test<String>[] t3 = ac.create(10);

最後のケースでコンパイラが警告を表示しないのはなぜですか?それでも配列を作成するためにrawタイプを使用しますよね?

55
Vladimir M.

[〜#〜] jls [〜#〜] は、ジェネリック型のコンストラクターへのメソッド参照がジェネリックパラメーターを推論することを指定することです。またはコンストラクターがジェネリックである場合、適切な型引数は推論されるか、明示的に提供されます。」後でArrayList::newを例として、それを「ジェネリッククラスの推定型引数」として説明し、そのためArrayList::new(ではなくArrayList<>::new)は、引数を推測する構文です。

クラスを考える:

public static class Test<T> {
    public Test() {}
}

これは警告を出します:

Test<String> = new Test(); // No <String>

しかし、これはしません:

Supplier<Test<String>> = Test::new; // No <String> but no warning

Test::newは暗黙的に汎用引数を推測します。

したがって、配列コンストラクターへのメソッド参照は同じように機能すると想定しています。

10

それでも配列を作成するためにrawタイプを使用しますよね?

Javaジェネリックはコンパイル時の錯覚にすぎないため、生の型はもちろん配列を作成するために実行時に使用されます。

最後のケースでコンパイラが警告を表示しないのはなぜですか?

はい、Test[]からTest<String>[]への未チェックのキャストがまだ発生しています。匿名のコンテキストで舞台裏で起こっているだけです。

Test<String>[] t3 = ((IntFunction<Test<String>[]>) Test[]::new).apply(10);

匿名メソッド はダーティな作業を行っているため、チェックされていないキャストはマネージコードから事実上消えます。

5
Patrick Parker