Java での汎用配列作成エラーの解決

Mehvish Ashiq 2023年10月12日
  1. Java での generic array creation エラーのデモ
  2. Java での generic array creation エラーの考えられる原因
  3. Java での generic array creation エラーを根絶するために考えられる解決策
Java での汎用配列作成エラーの解決

このチュートリアルでは、コード サンプルを介して 汎用配列の作成 エラーを示し、汎用配列の作成中にこのエラーが発生する理由を強調します。 この議論は、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() メソッドは、指定された次元 (配列のサイズ) とコンポーネント タイプを使用して新しい配列を作成します。

著者: Mehvish Ashiq
Mehvish Ashiq avatar Mehvish Ashiq avatar

Mehvish Ashiq is a former Java Programmer and a Data Science enthusiast who leverages her expertise to help others to learn and grow by creating interesting, useful, and reader-friendly content in Computer Programming, Data Science, and Technology.

LinkedIn GitHub Facebook

関連記事 - Java Error