かとじゅんの技術日誌

技術の話をするところ

ジェネリック型配列は作れるか?

ごきげんうるわしゅぅ。

さて、今回はジェネリックスの話題。
ジェネリックスになれてくるとうっかり書いてしまうのが、以下のコード。

public class MyArray<E>{
    private E[] elements;
    public MyArray(int n){
        elements = new E[n];
    }
    public E get(int index){
        return elements[index];
    }
    public void set(int index, E value){
        elements[index] = value;
    }
}

これは機能しそうですが、実際には以下でコンパイルエラーになります。

        elements = new E[n];

え?なぜできないの?って考えてしまうのですが、Eなどの具象化不可能型*1は配列を生成できないのです。

回避方法その1

えぇい、Listにしてしまえー。パフォーマンスは落ちるだろうけど。

List<E> elements;

回避方法その2

まさに、ArrayListソースコードにあったwww JDKのソース読んでてよかたーwww

ArrayListクラスの中

* Arrayだけに内部は固定長の配列です。

余談ですが、ArrayList<E>のE型ではなくObjectで管理されるんですね。

何気なく言及しているのですが、これがずばり回避方法。そもそもEの配列でなくObjectの配列で管理し、外部とのやり取りにはEを使う方法。(本を買う余裕がなくてもJDKのソースを読めばよいわけですね。なるほどー)

ArrayListですが、内部の配列はObject配列になっています。

    private transient Object[] elementData;

当然追加する際は難なく追加可能。

    public boolean add(E e) {
	ensureCapacity(size + 1);  // Increments modCount!!
	elementData[size++] = e;
	return true;
    }

要素を取得する場合はE型でキャストして返す。

    public E get(int index) {
	RangeCheck(index);

	return (E) elementData[index];
    }

ジェネリック型配列は作れないが、上記の回避方法で要件を満たすことができるかもしれない。

*1:実行時の表現がコンパイル時より少ない表現の型