2011-09-02 5 views
5

私は可変引数を使用する方法がありますが特色:リストの内容をvarargsメソッドに渡すにはどうしたらいいですか?

void add(Animal ...); 

を、代わりに.add(dog, cat)を行うので、私は、要素数が不明と動物のリストを持っている

List<Animal> i = new ArrayList<Animal>(); 
i.add(dog); 
i.add(cat); 

として追加呼び出したいですこのリストの要素

私は配列を使うことができると思いますが、.add(i.toArray())を実行すると、コンパイラエラーが発生します。

これを行う適切な方法は何ですか?

+0

質問は分かりません。独自のメソッド'add(Animal ...) 'を作成しましたが、ArrayList.add(Object)を呼び出すのではなく、自分のものではありません。何故ですか?コードの文脈で質問を編集してください。あなたの'add 'メソッド内にそのコードブロックがありますか?あなたの唯一の問題は、Object []をAnimal []にキャストすることができないということなので、@Tom answerに従ってください。 – aalku

+0

将来の注意:コンパイラエラーがある場合は、完全なエラーメッセージとこのメッセージに関連するソースコード行をコピーしてください。 –

答えて

10

それはです:

add(i.toArray(new Animal[i.size()])) 

List.toArrayは関係なく、リスト上の型引数の、Object[]を返します:あなたはnew List<String>().toArray()を書く場合でも、あなたはObject[]を取得します。ただし、version of toArray that takes an array to fillは、正しい型の配列を返します。new List<String>().toArray(new String[0])と書くと、String[]が得られます。渡す配列のサイズは、リストのサイズと一致する必要はありませんが、確実に行うことをお勧めします。

これは、最終的には、ジェネリックのややこしい機能のためです。一見すると、String[]List<String>は基本型の意味が似ていると思うかもしれません。一つは文字列の配列、もう一つは文字列のリストです。

しかし、実際には非常に異なっています。

配列は言語プリミティブであり、その型がベーキングされています。 16進エディタを使用してJVMのメモリ内の配列インスタンスを見た場合、保持しているオブジェクトのタイプのレコードを(近くのどこかに)見つけることができます。つまり、未知のコンポーネントタイプの配列のインスタンスを取る場合は、find out what that type isとすることができます。逆に、create an instance of an arrayに行く場合は、必要なコンポーネントの種類を知る必要があります。

Listは、他の一方で、Javaで大まかに言えば、それはコンパイラに存在するものですが、実行時に(コンパイラがあなたをすることを確認することができない、ということを意味し、type erasureで実装されたジェネリックを使用していますそれは正しくなるが、JVMはできない)。これにより、シンプルで効率的な実装が可能になります(JVMを変更せずにジェネリック以前のJavaに追加するだけのシンプルな実装です)が、いくつかの欠点があります。特に、実行時に型引数タイプ引数はコンパイラにのみ存在するため、ジェネリッククラスの特定のインスタンスでは、 toArray()を処理するのはListインスタンスまでですので、できることはObject[]を作成することだけです。それは、使用するより具体的なタイプのことを知らないだけです。これを見ているの

一つの方法は、List sが彼らのタイプの一環として、型引数を持っているのに対し、およびオブジェクトクラスを持っていますが、変数は型を持っているので、配列は、そのクラスの一環として、型引数を持っているということです、オブジェクトを保持する変数からのみ、オブジェクトの型引数(List)を取得することはできません(脇に、配列を保持する変数から配列の型引数を取得することはできません(考慮する)。しかし、それは本当に重要ではありません。なぜなら、変数はヌルでない限りオブジェクトを保持できるからです。

は、コードにこれを煮詰めるために、問題がある:

public <E> E[] createSimilarlyTypedArray(List<E> list) { 
    Class<E> componentType = list.???; // there is no way to do this 
    return Arrays.newInstance(componentType, list.size()); 
} 
+0

配列が十分大きい場合は配列を使用し、そうでない場合は新しい配列を割り当てます。 – aalku

+0

ジェネリック型が設定されていないリストでi.toArray(new Animal [])を呼び出すと、タイプキャスト例外が発生しませんか? –

+1

@ベンジャミン:いいえ、あなたはしません。 'Arrays 'を実行してみてください。 asList( "hello")。toArray(new String [1]); ' - 完全に動作します。静的には、このバージョンの 'toArray'は型パラメーターを所有している' List'(奇妙ではありますが正しい!)ではなく、動的に、実行時に 'List'の型消去されました。 –

0

私はそれがエラーになります.add(i.toArray())を行う際に、それを行うための適切な方法 ものです?

foo.addAll(i)を使用し、必要に応じてfooを配列に変換します。

0

void add(Animal...)には、AnimalクラスのオブジェクトまたはAnimalオブジェクトを含む配列が必要です。あなたはObjectクラスのオブジェクトを配列に渡します。リストにそのような一般的なタイプを与える:

ジェネリック医薬品の
add(animals.toArray(new Animal[animals.size()]); 

詳細に記載されていますので、は次のようにあなたの方法に、配列に変換しながら、

List<Animal> animals = new ArrayList<Animal>(); 
animals.add(dog); 
animals.add(cat) 

はその後、引数としてリストを解析Java API

http://download.oracle.com/javase/1,5.0/docs/guide/language/generics.html

+1

"Animal'オブジェクトを持つ配列を期待するよりも、それ自身の型が' Animal [] 'の配列が必要です。ゼロ引数型のtoArrayは、 'Animal'オブジェクトを持つ配列を作成します。配列は基本的に' new Object [] {new Animal()} 'です。しかし、必要なのは 'new Animal [] {new Animal()}'です。配列とジェネリックスの合流点は本当に危険なパッチです! –

関連する問題