これはコンパイルされません。提案はありがたいです。
...
List<Object> list = getList();
return (List<Customer>) list;
コンパイラによると:List<Object>
をList<Customer>
にキャストできません
最初にオブジェクトにアップキャストすることで、いつでもオブジェクトを任意のタイプにキャストできます。あなたの場合:
(List<Customer>)(Object)list;
実行時には、リストにCustomerオブジェクトのみが含まれていることを確認する必要があります。
批評家は、そのようなキャストはあなたのコードに何か問題があることを示していると言います。それを避けるために型宣言を微調整できるはずです。ただし、Javaジェネリックは複雑すぎるため、完全ではありません。ランタイムの型を非常によく知っていて、何をしようとしているかが安全であることを知っていても、コンパイラを満足させるきれいな解決策があるかどうか分からないことがあります。その場合は、必要に応じて粗鋳造を行ってください。そうすれば、家に帰ることができます。
これは、顧客はオブジェクトですが、顧客のリストではないオブジェクトのリストだからです。もしそうなら、顧客のリストにanyオブジェクトを置くことができます。
他のコードに応じて、ベストアンサーは異なる場合があります。試してください:
List<? extends Object> list = getList();
return (List<Customer>) list;
または
List list = getList();
return (List<Customer>) list;
ただし、このような未チェックのキャストを行うことはお勧めできません。
ダブルキャストを使用できます。
return (List<Customer>) (List) getList();
Java 8の場合 ストリーム :
時にはブルートフォースキャスティングで問題ありません:
List<MyClass> mythings = (List<MyClass>) (Object) objects
しかし、より汎用性の高いソリューションは次のとおりです。
List<Object> objects = Arrays.asList("String1", "String2");
List<String> strings = objects.stream()
.map(element->(String) element)
.collect(Collectors.toList());
たくさんの利点がありますが、1つは、リストに何が含まれているかわからない場合に、リストをよりエレガントにキャストできることです。
objects.stream()
.filter(element->element instanceof String)
.map(element->(String)element)
.collect(Collectors.toList());
私はJavaプログラマではありませんが、.NETおよびC#では、この機能は反分散または共分散と呼ばれます。まだベータ版であるため使用していない.NET 4.0の新機能であるため、これらのことについてはまだ詳しく調べていません。したがって、2つの用語のどちらが問題を説明しているのかわかりませんが、これに関する技術的な問題。
あなたがキャストを許可されたと仮定しましょう。注:cast、それはあなたが言ったことですが、可能性のある2つの操作、castingとconvertingがあります。
変換とは、新しいリストオブジェクトを取得することを意味しますが、キャストと言います。これは、あるオブジェクトを一時的に別のタイプとして扱うことを意味します。
これが問題です。
以下が許可された場合にどうなりますか(注、キャストの前に、オブジェクトのリストには実際にはCustomerオブジェクトのみが含まれていると仮定しています。そうしないと、この仮想バージョンのJavaでもキャストが機能しません)。
List<Object> list = getList();
List<Customer> customers = (List<Customer>)list;
list.Insert(0, new someOtherObjectNotACustomer());
Customer c = customers[0];
この場合、これは顧客ではないオブジェクトを顧客として扱うことを試み、リスト内のフォームまたは割り当てからのいずれかの時点でランタイムエラーを取得します。
ただし、ジェネリックはコレクションなどのタイプセーフなデータ型を提供するものと想定されており、Wordを「保証」することを好むため、この種のキャストとそれに続く問題は許可されていません。
.NET 4.0(私はあなたの質問がJavaについてだったことを知っています)では、これは許可されます非常に特定の場合、ここでコンパイラはあなたがする操作が安全であることを保証できます、このタイプのキャストは許可されません。 Javaについても同じことが言えますが、Java言語に共変および反変を導入する計画については不明です。
うまくいけば、私よりもJavaの知識のある人がJavaの将来または実装の詳細を教えてくれるでしょう。
別のアプローチは、Java 8ストリームを使用することです。
List<Customer> customer = myObjects.stream()
.filter(Customer.class::isInstance)
.map(Customer.class::cast)
.collect(toList());
リストを繰り返し処理し、すべてのオブジェクトを1つずつキャストする必要があります
List<Customer> cusList = new ArrayList<Customer>();
for(Object o: list){
cusList.add((Customer)o);
}
return cusList;
list.stream().forEach(x->cusList.add((Customer)x))
return cuslist;
List<Object>
とList<Customer>
が同じ継承ツリーにないため、できません。
List<Customer>
を取るList<Object>
クラスに新しいコンストラクターを追加し、リストを反復して各Object
をCustomer
にキャストしてコレクションに追加できます。呼び出し元のList<Object>
にCustomer
以外のものが含まれている場合、無効なキャスト例外が発生する可能性があることに注意してください。
汎用リストのポイントは、それらを特定のタイプに制限することです。 anythingを含むリスト(注文、製品など)を取得し、顧客のみを取得できるリストに絞り込もうとしています。
リストで何をしたいかによっては、List<Customer>
にキャストする必要さえありません。 Customer
オブジェクトのみをリストに追加する場合は、次のように宣言できます。
...
List<Object> list = getList();
return (List<? super Customer>) list;
これは合法です(まあ、合法ではなく、正しい-リストは「顧客に対するスーパータイプ」です)、そして単に追加するメソッドにそれを渡す場合オブジェクトをリストに追加すると、上記の一般的な境界で十分です。
一方、リストからオブジェクトを取得して、Customersとして強く入力させたい場合は、運が悪くなります。リストはList<Object>
であるため、コンテンツが顧客であることを保証するものではないため、取得時に独自のキャストを提供する必要があります。 (または、絶対に、リストにCustomers
のみが含まれ、他の回答の1つからのダブルキャストを使用することを二重に確認しますが、コンパイル時の型安全性を完全に回避していることを認識してくださいこの場合はジェネリックから取得します)。
大まかに言えば、メソッドを記述するときに受け入れられる可能性のある最も広いジェネリックな境界を考慮することは常に良いことです。リストから読み取るだけの場合は、List<? extends T>
の代わりにList<T>
を使用します。たとえば、これにより、呼び出し側に渡されますmuch渡すことができる引数のスコープが増えますまた、ここで発生しているような回避可能な問題に遭遇する可能性が低くなります。
新しいリストを作成し、それに要素を追加できます。
例えば:
List<A> a = getListOfA();
List<Object> newList = new ArrayList<>();
newList.addAll(a);
最善の策は、新しいList<Customer>
を作成し、List<Object>
を反復処理し、各項目を新しいリストに追加して、それを返すことです。
他の人が指摘したように、List<Object>
はList<Customer>
ではないため、それらを保存することはできません。できることは、インプレース型チェックを行うリストにビューを定義することです。 Google Collections を使用すると:
return Lists.transform(list, new Function<Object, Customer>() {
public Customer apply(Object from) {
if (from instanceof Customer) {
return (Customer)from;
}
return null; // or throw an exception, or do something else that makes sense.
}
});
上記のBozhoと同様です。このメソッドを使用して、ここで回避策を実行できます(私自身は好きではありませんが)。
public <T> List<T> convert(List list, T t){
return list;
}
はい。リストを要求されたジェネリック型にキャストします。
上記の場合、次のようなコードを実行できます。
List<Object> list = getList();
return convert(list, new Customer());