次の文の意味を誰か説明してくれませんか :
具象化できないコンポーネント型を持つ配列の作成は許可されていません。
次の文の意味を誰か説明してくれませんか :
具象化できないコンポーネント型を持つ配列の作成は許可されていません。
具象化できないコンポーネント型を持つ配列の作成は許可されていません。
実際には、ジェネリック配列の作成が違法であることを意味します。
new T[...] // prohibited
配列には実行時のコンポーネントに関する情報が含まれるため、汎用配列は使用できません。これは、ジェネリックには当てはまりません。ジェネリックはコンパイラ レベルで実装されます。したがって、配列を作成するときは、コンポーネントの型を事前に知っておく必要があります。
Java プログラミング言語では、パラメーター化された型の配列の作成が許可されていません。つまり、new T [] は許可されていません。
配列の要素型が具体化できない場合 (§4.7)、仮想マシンは前の段落で説明したストア チェックを実行できませんでした。これが、具体化できない型の配列の作成が禁止されている理由です。要素型が具体化できない配列型の変数を宣言することはできますが、それらに値を代入しようとすると未チェックの警告が発生します (§5.1.9)。
詳細については、こちら をご覧ください。
以下は、ジェネリック型で varargs を使用した場合に何が問題になるかを示すコード例です。
public class ArrayBuilder {
public static <T> void addToList(List<T> listArg, T... elements) {
for (T x : elements) {
listArg.add(x);
}
}
public static void faultyMethod(List<String>... l) {
Object[] objectArray = l; // Valid
objectArray[0] = Arrays.asList(42);
String s = l[0].get(0); // ClassCastException thrown here
}
public static void main(String[] args) {
List<String> stringListA = new ArrayList<String>();
List<String> stringListB = new ArrayList<String>();
ArrayBuilder.addToList(stringListA, "Seven", "Eight", "Nine");
ArrayBuilder.addToList(stringListA, "Ten", "Eleven", "Twelve");
List<List<String>> listOfStringLists = new ArrayList<List<String>>();
ArrayBuilder.addToList(listOfStringLists, stringListA, stringListB);
ArrayBuilder.faultyMethod(Arrays.asList("Hello!"),
Arrays.asList("World!"));
}
}
コンパイラは、varargs メソッドを検出すると、varargs 仮パラメーターを配列に変換します。ただし、the Java programming language does not permit the creation of arrays of parameterized types
. メソッド ArrayBuilder.addToList で、コンパイラは varargs 仮パラメータT...
要素を仮パラメータT[]
要素である配列に変換します。ただし、型消去のため、コンパイラはvarargs
仮パラメーターをObject[]
要素に変換します。その結果、ヒープ汚染の可能性があります。
次のステートメントは、varargs 仮パラメーターl
を Object 配列 objectArgs に割り当てます。
Object[] objectArray = l;
このステートメントは、ヒープ汚染を引き起こす可能性があります。varargs 仮パラメーター l のパラメーター化された型と一致する値は、変数 objectArray に割り当てることができるため、l に割り当てることができます。ただし、コンパイラはこのステートメントで未チェックの警告を生成しません。コンパイラは、varargs 仮パラメーターList<String>
... l を仮パラメーターList[]
l に変換したときに、既に警告を生成しています。このステートメントは有効です。変数 l の型List[]
は であり、これは のサブタイプですObject[]
。
したがって、次のステートメントに示すように、任意の型の List オブジェクトを objectArray 配列の任意の配列コンポーネントに代入しても、コンパイラは警告またはエラーを発行しません。
objectArray[0] = Arrays.asList(42);
このステートメントは、ObjectArray 配列の最初の配列コンポーネントに、Integer 型のオブジェクトを 1 つ含む List オブジェクトを代入します。
次のステートメントで ArrayBuilder.faultyMethod を呼び出すとします。
ArrayBuilder.faultyMethod(Arrays.asList("Hello!"), Arrays.asList("World!"));
実行時に、JVM は次のステートメントで ClassCastException をスローします。
// ClassCastException thrown here
String s = l[0].get(0);
そのリンクをさらに読んでいたら、次のステートメントが見つかりました: -
Pair<String,String> is not a reifiable type, that is, it loses information as a
result of type erasure and is at runtime represented as the raw type Pair
instead of the exact type Pair<String,String>
JLSの詳細- Arrays : -
討論
配列の要素型が具体化できない場合 (§4.7)、仮想マシンは前の段落で説明したストア チェックを実行できませんでした。これが、具体化できない型の配列の作成が禁止されている理由です。要素型が具体化できない配列型の変数を宣言することはできますが、それらに値を代入しようとすると未チェックの警告が発生します (§5.1.9)。