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タイプを使用しますよね?
[〜#〜] 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
は暗黙的に汎用引数を推測します。
したがって、配列コンストラクターへのメソッド参照は同じように機能すると想定しています。
それでも配列を作成するためにrawタイプを使用しますよね?
Javaジェネリックはコンパイル時の錯覚にすぎないため、生の型はもちろん配列を作成するために実行時に使用されます。
最後のケースでコンパイラが警告を表示しないのはなぜですか?
はい、Test[]
からTest<String>[]
への未チェックのキャストがまだ発生しています。匿名のコンテキストで舞台裏で起こっているだけです。
Test<String>[] t3 = ((IntFunction<Test<String>[]>) Test[]::new).apply(10);
匿名メソッド はダーティな作業を行っているため、チェックされていないキャストはマネージコードから事実上消えます。