Java での汎用配列作成エラーの解決
-
Java での
generic array creation
エラーのデモ -
Java での
generic array creation
エラーの考えられる原因 -
Java での
generic array creation
エラーを根絶するために考えられる解決策
このチュートリアルでは、コード サンプルを介して 汎用配列の作成
エラーを示し、汎用配列の作成中にこのエラーが発生する理由を強調します。 この議論は、Object
配列と reflect
機能を使用してジェネリック配列を作成する方法を学習する解決策につながります。
Java での generic array creation
エラーのデモ
コード例 (DemoGenArray.java
クラス):
import java.util.Arrays;
public class DemoGenArray<T> {
private T[] genericArray;
DemoGenArray(int size) {
genericArray = new T[size]; //<----This Line Has Generic Array Creation Error
}
public T get(int index) {
return (T) genericArray[index];
}
public void set(int index, T item) {
genericArray[index] = item;
}
@Override
public String toString() {
return Arrays.toString(genericArray);
}
}
このクラスでは、指定された配列 size
でジェネリック配列を作成して初期化しようとします。 さらに、配列に要素を追加し、指定された index
から項目を個別に返します。
toString()
は配列全体を一度に返します。
問題は、コンストラクターで指摘している行に generic array creation
エラーがあることです。 このエラーの考えられる原因を調べて、解決策に進むのに役立ててみましょう。
Java での generic array creation
エラーの考えられる原因
コードでジェネリック配列を作成しようとしていますが、これは Java では不可能です。 これは、Java がこれらの構文の動作を明示的に停止することを意識的に決定したためです。
ジェネリックはそうではありませんが、Javaでは配列は共変です(サブタイプをそのスーパータイプ参照に割り当てることができます)。
private T[] genericArray;
genericArray = new T[size];
上記の 2 行のコードは、以下に示すものと同じです。 それらのいずれかを使用できます。
private T[] genericArray = new T[size];
これは、Java が実装する type-erasure
が原因で発生します。 これは、Java コンパイラーによって実行されるプロセスです。
ジェネリックのパラメーター化された型を削除し、バイト コードの生の型にマップします。
バイトコードにはジェネリックに関する詳細が含まれていないことに注意してください。 型 T
の使用は、コンパイル時には問題ありませんが、実行時には意味がありません。
他の方法で、この 制限 を回避できます。コード例を以下に示します。 以下でそれぞれを学びましょう。
Java での generic array creation
エラーを根絶するために考えられる解決策
既に知っているように、コンパイラは実行時にパラメーター化された型に関する情報を持っていません。 したがって、ジェネリクスを使用する必要がある場合はいつでも、配列を使用する代わりに Java Collections
フレームワークのリスト コンポーネントを優先して使用することをお勧めします。
ただし、配列のような一般的な構造を作成することはできますが、この解決策は、それがチェック済み
か未チェック
かによって異なります。 チェックされていない
場合は、Object
配列を使用します。
checked
の場合、Java の reflect
機能を使用できます。 それぞれがどのように機能するか見てみましょう。
解決策 1: Object
配列を使用する
コード例 (DemoGenArray.java
クラス):
import java.util.Arrays;
public class DemoGenArray<T> {
private Object[] genericArray;
DemoGenArray(int size) {
genericArray = new Object[size];
}
public T get(int index) {
return (T) genericArray[index];
}
public void set(int index, T item) {
genericArray[index] = item;
}
@Override
public String toString() {
return Arrays.toString(genericArray);
}
}
コード例 (GenArray.java
クラス):
public class GenArray {
public static void main(String[] args) {
DemoGenArray<String> strArray = new DemoGenArray(3);
strArray.set(0, "one");
strArray.set(1, "two");
strArray.set(2, "three");
DemoGenArray<Integer> intArray = new DemoGenArray(3);
intArray.set(0, 10);
intArray.set(1, 20);
intArray.set(2, 30);
DemoGenArray<Double> doubleArray = new DemoGenArray(3);
doubleArray.set(0, 15.0);
doubleArray.set(1, 110.0);
doubleArray.set(2, 10.0);
System.out.println("Integer Array: " + intArray);
System.out.println("String Array: " + strArray);
System.out.println("Double Array: " + doubleArray);
}
}
出力:
Integer Array: [10, 20, 30]
String Array: [one, two, three]
Double Array: [15.0, 110.0, 10.0]
ここでは、DemoGenArray
クラスが unchecked
(弱い型付け) であるため、Object
配列を使用してジェネリック配列をシミュレートします。 引数として渡されたオブジェクトに対して型チェックが実行されないことがわかっている場合は、このアプローチを使用できます。
さらに、一般的な get()
および set()
メソッドを使用して、それぞれ値を返し、値を設定します。 get()
メソッドは T
への明示的なキャストを使用します。ここで、T
はジェネリックのプレースホルダーのように機能し、任意の値/要素を表します。
set()
および get()
メソッドを使用し、ユーザーが直接 Object
配列にアクセスできないようにすると、これはうまく機能します。 main()
メソッドを含むGenArray
クラスに来ます。
ここでは、DemoGenArray
クラスのインスタンスを作成します。
DemoGenArray
クラスをインスタンス化してそれらに値を設定する際に、必要な型を渡します。 その後、toString()
メソッドを使用して、すべてのインスタンスの内容を書き込みます。
解決策 2: reflect
機能を使用する
コード例 (DemoGenArray.java
クラス):
import java.lang.reflect.Array;
import java.util.Arrays;
public class DemoGenArray<T> {
private T[] genericArray;
DemoGenArray(Class<T> classType, int size) {
genericArray = (T[]) Array.newInstance(classType, size);
}
public T get(int index) {
return (T) genericArray[index];
}
public void set(int index, T item) {
genericArray[index] = item;
}
@Override
public String toString() {
return Arrays.toString(genericArray);
}
}
コード例 (GenArray.java
クラス):
public class GenArray {
public static void main(String[] args) {
DemoGenArray<String> strArray = new DemoGenArray(String.class, 3);
strArray.set(0, "one");
strArray.set(1, "two");
strArray.set(2, "three");
DemoGenArray<Integer> intArray = new DemoGenArray(Integer.class, 3);
intArray.set(0, 10);
intArray.set(1, 20);
intArray.set(2, 30);
DemoGenArray<Double> doubleArray = new DemoGenArray(Double.class, 3);
doubleArray.set(0, 15.0);
doubleArray.set(1, 110.0);
doubleArray.set(2, 10.0);
System.out.println("Integer Array: " + intArray);
System.out.println("String Array: " + strArray);
System.out.println("Double Array: " + doubleArray);
}
}
出力:
Integer Array: [10, 20, 30]
String Array: [one, two, three]
Double Array: [15.0, 110.0, 10.0]
ここでは、リフレクション クラスを使用して、型が実行時にのみわかる汎用配列を作成しています。 このソリューションは、DemoGenArray
クラスの 2つの違いを除いて、ソリューション 1 と似ています。
まず、配列の型とサイズの 2つの引数を受け取る DemoGenArray
クラスにコンストラクターがあります。 次に、Array.newInstance()
メソッドを使用して genericArray
を初期化します。
Array.newInstance()
メソッドは、指定された次元 (配列のサイズ) とコンポーネント タイプを使用して新しい配列を作成します。