12

メソッド(のtoArray実装を選択しましょうjava.util.ArrayList)は次のとおりです。

class ArrayList<E> ....{
    public <T> T[] toArray(T[] a){
        if(a.length < size)
            return (T[]) Arrays.copyof(elementData, size, a.getClass());
        System.arraycopy(elementData, 0, a, 0, size);
        if(a.length > size)
            a[size] = null;
        return a;
    }    
}

この場合<E>の代わりに使用できるのだろうか?<T>お気に入り

public E[] toArray(E[] a){
      if(a.length < size)
             return (E[]) Arrays.copyof(elementData, size, a.getClass());
      System.arraycopy(elementData, 0, a, 0, size);
      if(a.length > size)
            a[size] = null;
      return a;
}    

ArrayListクラス自体はすでにジェネリック<E>であるため、新しいジェネリック型の代わりにそれを使用でき<T>ますか?

4

2 に答える 2

12

ジョンBの答えはアイデアをうまく​​カバーしていると思います-少し詳しく説明したいと思います。

まず、質問で提案したメソッドシグネチャを見てみましょう。

public E[] toArray(E[] a)

Johnが説明したように、この署名は柔軟性が低くなります。ArrayList<Integer>をにダンプしたい場合Number[]、このメソッドでは許可されません。Collections APIは、その柔軟性を実現したいと考えています。

残念ながら、現状のメソッドでは、配列のタイプをコンパイル時にチェックすることはできません。これは、発生していると思われる問題です。toArrayによって宣言されているのドキュメントでは、 「指定された配列のランタイムタイプが、このコレクション内のすべての要素のランタイムタイプのスーパータイプでない場合」にスローされる可能性があるとCollection説明されています。ArrayStoreException

その説明に基づくと、次の署名が理想的であるように思われます。

public <T super E> T[] toArray(T[] a)

一見すると、これにより、任意の正当なタイプの配列を渡してデータを取り込むことができるように見えますが、実行時ではなくコンパイル時に型チェックが提供されます。では、なぜこの署名が代わりに宣言されないのですか?

さて、この構文:

 <T super E>

言語ではサポートされていません。しかし、このタイプチェックがとにかく機能しないという事実からあなたをそらすのは簡単です。問題は、パラメーター化された型とは異なり、配列は共変であるということです。Integer[]Number[]ですObject[]。_ したがって、での架空の署名を考えると<T super E>、を呼び出しtoArrayArrayList<Number>を渡したInteger[]場合でも、コンパイルされ、リストの内容によっては実行時に失敗する可能性があります。

つまり、渡された配列のコンポーネントタイプの下限は、何の役にも立ちません。

于 2012-09-11T04:59:19.837 に答える
6

ポイントは、<T>必要な配列が の基本クラスである場合ですE。たとえば、Eis ですHashMapが、目的の配列は でしたMap[]。これtoArrayにロックダウンされている場合はE不可能です。

このタイプのものは、型消去のために一般的なコレクション/型では必要ありません。ただし、配列には型消去がないため、配列の型は非常に重要になる可能性があります。

于 2012-09-10T16:41:46.427 に答える