-2

次のコードを完全に汎用的にするにはどうすればよいですか?

なぜ私は書くことを許可されていません:

private E[]store = new E[length];

import java.util.Arrays;
public class MyArrayList<E> {
    private int size = 0;
    private int length = 10;

    private Object [] store = new Object[length];
        public E get(int index){
        return (E)store[index];
    }

    public void add(E item){
        if(size >= store.length -5){
            increment(store);
        }
        store[size++] = item;
    }

    private <T> void increment(T[] store2) {
        store = Arrays.copyOf(store2, store2.length * 2);
    }

    public int size(){
        return size;
    }
}
4

2 に答える 2

2

コンポーネントの型が型パラメーターである配列変数のみを宣言できますが、対応する配列オブジェクトを作成することはできません。E型消去のため、実行時の型は不明です。コンパイラは、不明なコンポーネント タイプの配列を作成する方法を知りません。

同様に、具体的なパラメーター化された型の配列を作成することはできません。

回避策は、次の方法を使用するArray.newInstanceことです。

Class<E> clazz;
E[] array = (E[])Array.newInstance(clazz, length) ;

ただし、これによりUnchecked Cast警告が表示されます。注釈を使用して警告を抑制することができます。ただし、そのメソッドに引数を渡す必要があります。これは、型パラメーターのクラス型である必要があります。Array.newInstanceObjectE[]@SuppressWarningsclazzE


配列とジェネリック型の間には大きな違いがあります。つまり、配列は具体化されています( @Markoの回答ですでに述べたように)。このトピックに関する本のEffective Java - Item 29から、段落を追加します。

これは、配列が実行時に要素の型を認識して適用することを意味します。前述のように、String を Long の配列に格納しようとすると、ArrayStoreException が発生します。対照的に、ジェネリックは消去によって実装されます [JLS、4.6]。これは、コンパイル時にのみ型制約を適用し、実行時に要素型情報を破棄 (または消去) することを意味します。消去は、ジェネリック型がジェネリックを使用しないレガシー コードと自由に相互運用できるようにするものです (項目 23)。

これらの基本的な違いのため、配列とジェネリックはうまく混在しません。たとえば、ジェネリック型、パラメーター化された型、または型パラメーターの配列を作成することは違法です。次の配列作成式はいずれも有効ではありません: new List<E>[]new List<String>[]new E[]. いずれも、コンパイル時に一般的な配列作成エラーが発生します。

于 2013-08-17T17:49:38.197 に答える
2

配列要素型は、ジェネリック型パラメーターとは異なり、具体化されたエンティティです。つまり、new Integer[]は とは異なる種類のオブジェクトを作成しますnew Double[]。それに対して、new ArrayList<Integer>()は とまったく同じオブジェクトを作成しますnew ArrayList<Double>()

ジェネリック型パラメーターがランタイム コードから消去されるため、JVM は、必要な正しい型の配列をインスタンス化することができなくなります。

于 2013-08-17T17:49:40.980 に答える