List <Object>をList <MyClass>にキャストする方法


回答:


156

オブジェクトを最初にObjectにアップキャストすることで、いつでもオブジェクトを任意の型にキャストできます。あなたの場合:

(List<Customer>)(Object)list; 

実行時には、リストにCustomerオブジェクトのみが含まれていることを確認する必要があります。

批評家は、そのようなキャストはコードに問題があることを示していると言います。それを避けるために型宣言を微調整できるはずです。しかし、Javaジェネリックは複雑すぎて、完璧ではありません。ランタイムタイプをよく知っていて、実行しようとしていることが安全であるとわかっていても、コンパイラーを満足させるための素晴らしい解決策があるかどうかわからない場合があります。その場合は、必要に応じて粗鋳造を行うだけで、家に帰ることができます。


8
これも必要@SuppressWarnings("unchecked")です。to (List)ではなくto にアップキャストすることもできます(Object)
200_成功2016

36

これは、顧客オブジェクトですが、顧客リストはオブジェクトのリストではないためです。ある場合は、顧客のリストに任意のオブジェクトを配置できます。


2
いいえ、そうではありません。上記が許可されていれば、タイプセーフを回避できます。キャストとは、新しいリストを作成してアイテムをコピーすることを意味しないことに注意してください。これは、単一のインスタンスを別のタイプとして処理することを意味します。したがって、タイプセーフが保証されない、Customer以外のオブジェクトが含まれている可能性があるリストがあります。これは、Java自体とは関係ありません。この機能ではJavaが暗い時代に行き詰まっていると感じているので、代わりにこれがどのように機能すべきかを説明するように要求します。
ラッセV.カールセン2014

1
@ BrainSlugs83(List <Customer>)(Object)list;
Muthu Ganapathy Nathan 2014

@ LasseV.Karlsenキャストについてではなく、変換について話している。タイプセーフを回避するのではなく、強制します。ジェネリックのJavaの実装、演算子のオーバーロードの欠如、拡張メソッド、および他の多くの最新の設備により、私は絶望的に失望しました。-と呼ばれるもの-一方、.NETは、このために2つの別個の拡張メソッド有する.Cast<T>()と呼ばれるものを.OfType<T>()。前者は各要素に対してキャストを実行し(必要な例外をスロー)、後者はキャストできない要素を除外します(使用シナリオに応じて選択します)。
BrainSlugs83 2014年

1
@EAGER_STUDENT実際に機能する可能性のあるJavaを超えないようにします(このばかげた型消去ビジネスはすべて試してみる必要があります...)-いいえ、そのようなコードは決して作成しません-失うタイプセーフ、コレクションの1つの要素がinstanceofCustomer でない場合はどうなりますか?
BrainSlugs83 14年

1
@ BrainSlugs83質問をした人は、特にキャストについて尋ねました。そして、Javaが参照する.NETメソッドのような関連するメソッドをまだ持っていない場合(これはまだ変換されていません)、それらを簡単に追加できるはずです。これは、特定の構文について尋ねられた当面の質問とはまったく直交しています。
ラッセV.カールセン2014年

35

他のコードによっては、最良の答えが異なる場合があります。試してください:

List<? extends Object> list = getList();
return (List<Customer>) list;

または

List list = getList();
return (List<Customer>) list;

ただし、このようなチェックされていないキャストを行うことはお勧めしません。


3
-1-これは非常に悪い習慣であり、 "Unchecked"アノテーションを使用しない限り、コンパイラーはそれについて文句を言うでしょう
kdgregory

24

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());

1
ただし、キャストよりもコピーの方が多くなります。
200_成功2016

受け入れられたanserで言及されているキャスティングは私にはうまくいきませんでした。また、私はJava 7を使用していましたが、GuavaがFluentIterableうまくいきました。
Sridhar Sarnobat

これは私が探していたものですが、構文を知りませんでした
Fueled By Coffee


8

私はJavaプログラマではありませんが、.NETおよびC#では、この機能は反変または共分散と呼ばれています。それらは.NET 4.0の新機能であるため、まだ詳しく説明していません。ベータ版であるため使用していません。2つの用語のどちらが問題を説明しているかはわかりませんが、これに関する技術的な問題。

あなたがキャストを許可されていたとしましょう。注:キャストと言います、それはあなたが言ったことですが、可能な2つの操作、キャスト変換があります。

変換とは、新しいリストオブジェクトを取得することを意味しますが、キャストとは、あるオブジェクトを別のタイプとして一時的に処理することを意味します。

これが問題です。

以下が許可された場合はどうなりますか(キャストの前は、オブジェクトのリストには実際にはCustomerオブジェクトのみが含まれていると想定しています。それ以外の場合、この仮想バージョンのjavaでもキャストは機能しません)。

List<Object> list = getList();
List<Customer> customers = (List<Customer>)list;
list.Insert(0, new someOtherObjectNotACustomer());
Customer c = customers[0];

この場合、これは顧客ではないオブジェクトを顧客として処理しようとし、リスト内のフォームまたは割り当てから、ある時点でランタイムエラーが発生します。

ただし、ジェネリックスは、コレクションなどのタイプセーフなデータ型を提供することになっています。また、「保証された」という言葉を投げかけたいので、この種のキャストは、以下の問題があるため、許可されていません。

.NET 4.0では(私は知っています、あなたの質問はJavaについてでした)、これはいくつかの非常に特殊なケースで許可さますが、コンパイラはあなたが行う操作が安全であることを保証できますが、一般的な意味でこのタイプのキャストは許可されている。同じことがJavaにも当てはまりますが、Java言語に共分散および反変を導入する計画についてはよくわかりません。

うまくいけば、私よりもJavaの知識が豊富な人に、Javaの将来や実装の詳細を教えてもらえますか。


3
Javaの未来は... Scalaです。真剣に、ジェネリックをJavaにボルトで固定した人は、Javaにやや似ているが、型には非常に精通している新しい言語を開発しました。型処理の非常に徹底的で一貫した実装です。どのScala機能がいつJavaにフローバックするかは、誰にもわからないと思います。
Carl Smotricz、2009

OPの質問に真に答える共分散の優れた説明。よくやった。
ケビンデイ

カール:Java開発者の一部がC#を作成すると思いましたか?:)とにかく、そうです、Javaは、おそらく、型付けが弱いものではなく、将来Scalaの方向に行く可能性が高いです。
Esko、

@Carl-Scalaでは、デフォルトでリストが不変であるという点で微妙な違いがあります。そのため、一般に、オブジェクトをCustomersのリストに追加する問題はありません。これを行うと、新しいObjectリストが取得されるためです。
ブライアンアグニュー2010

Er ...技術的にはこれは正しいですが、.NET 4.0より前でも-通常のIEnumerable拡張メソッド(.Cast <>と.OfType <>)でこれを行うことができました。強力な型の反復が必要なだけです。
BrainSlugs83 2014

7

別のアプローチは、Java 8ストリームを使用することです。

    List<Customer> customer = myObjects.stream()
                                  .filter(Customer.class::isInstance)
                                  .map(Customer.class::cast)
                                  .collect(toList());

1
ありがとう、このソリューションは、メソッドのリファレンスを使用して、とても美しいです
タン

1
誰かがそこまでスクロールダウンするとは思っていません
でした

3

リストを反復処理して、すべてのオブジェクトを1つずつキャストするだけです。


3

あなたはこのようなことをすることができます

List<Customer> cusList = new ArrayList<Customer>();

for(Object o: list){        
    cusList.add((Customer)o);        
}

return cusList; 

またはJava 8の方法

list.stream().forEach(x->cusList.add((Customer)x))

return cuslist;

2

あなたは理由ができないList<Object>List<Customer>同じ継承ツリーではありません。

List<Customer>クラスに新しいコンストラクターを追加してa を受け取りList<Object>、リストを繰り返し処理してそれぞれObjectをaにキャストし、Customerそれをコレクションに追加します。呼び出し元List<Object>がでないものを含んでいる場合、無効なキャスト例外が発生する可能性があることに注意してくださいCustomer

ジェネリックリストのポイントは、リストを特定のタイプに制限することです。何かを含むことができるリスト(注文、製品など)を取得して、顧客のみを取得できるリストに絞り込みます。


2

新しいリストを作成し、それに要素を追加できます。

例えば:

List<A> a = getListOfA();
List<Object> newList = new ArrayList<>();
newList.addAll(a);

1

あなたの最善の策は、新しいを作成しList<Customer>、を反復処理し、List<Object>各項目を新しいリストに追加して、それを返すことです。


1

他の人が指摘したように、a List<Object>はでないため、それらを保存してキャストすることはできませんList<Customer>。あなたができることは、その場で型チェックを行うリストのビューを定義することです。次のようなGoogleコレクションを使用します

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.
  }
});

1

上記のBozhoと同様。この方法を使用して、ここでいくつかの回避策を実行できます(私自身はそれが好きではありません)。

public <T> List<T> convert(List list, T t){
    return list;
}

はい。リストを要求されたジェネリック型にキャストします。

上記のケースでは、次のようなコードを実行できます。

    List<Object> list = getList();
    return convert(list, new Customer());

私はこの解決策が好きです。SuppressWarningsを追加する必要がある場合でも、安全でないすべてのキャストよりも1か所に追加することをお勧めします。
robson

1

リストの処理方法によっては、それをにキャストする必要がない場合もありますList<Customer>Customerリストにオブジェクトを追加するだけの場合は、次のように宣言できます。

...
List<Object> list = getList();
return (List<? super Customer>) list;

これは合法です(まあ、合法だけでなく、正しい -リストは「顧客へのスーパータイプ」です)。そして、リストにオブジェクトを追加するだけのメソッドにそれを渡す場合は、上記のこれには一般的な境界で十分です。

一方、リストからオブジェクトを取得して、Customersとして強く入力したい場合は、運が悪いため、当然です。このリストはList<Object>コンテンツであることを保証するものではないため、取得時に独自​​のキャストを提供する必要があります。(または、本当に、絶対に、リストCustomersには他の回答のいずれかからのダブルキャストのみが含まれ、使用されることを二重に確認してください。場合)。

大まかに言って、メソッドを書くときに許容できる最も広い一般的な境界を検討することは常に良いことです。リストから読み取るだけの場合List<? extends T>List<T>、たとえばの代わりに使用します。これにより、呼び出し元が渡すことができる引数の範囲がはるかに広くなり、呼び出し元と同様の回避可能な問題が発生する可能性が低くなります。ここで持っている。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.