5

フルーツのリストをリストに含まれるフルーツのサブクラスにキャストするのに問題があります。

public class Response {
    private List<Fruit> mFruitList;
    public List<Fruit> getFruitList() {
        return mFruitList;
    }
} 

public class Fruit {
}

public class Orange extends Fruit {
}

List<Fruit> oranges = response.getFruitList();

クラスオレンジのリストになるようにオレンジをキャストするにはどうすればよいですか? これは悪い設計パターンですか?基本的に、フルーツのリストであるサーバーから JSON 応答を取得しています。Web サービスへの特定の呼び出しごとに、取得する Fruit のサブクラスがわかっているので、その List を適切にキャストする必要があります。

4

5 に答える 5

7

Fruit のどのサブクラスを取得するかを特定の呼び出しごとに知っている場合は、リストをキャストする代わりにジェネリックを使用する必要があります。

public class Response<T extends Fruit> {
    private List<T> mFruitList;
    public List<T> getFruitList() {
        return mFruitList;
    }
} 

Response<Orange> response = // create
List<Orange> oranges = response.getFruitList();

編集: テンプレートとは、ジェネリック型を意味します。すみません、最近は C++ が多すぎました

于 2011-06-15T16:41:00.600 に答える
3

型キャストの背後にある全体的なアイデアは、コンパイラに「ねえ、私はこれについてあなたよりもよく知っている」と伝えることができるようにすることです。あなたのコードでは、コンパイラは実行時にリストに何が含まれるかを知ることができないため、 List<Fruit>to を安全にダウンキャストできません。List<Orange>

リストがインスタンスのみになることが確実Orangeであり、コードをダウンキャストしやすくする場合は、それを選択してください。

List<Orange> oranges = (List<Orange>) response.getFruitList();

もちろん、コンパイラは警告を表示します。これは、実行すべきではないと判断したことを実行しているためです。CastClassExceptionそして、あなたが間違っていた場合、JVM は最後に a を投げて笑うかもしれないことを知っておいてください!

于 2011-06-15T16:37:54.177 に答える
1

ジェネリクスは、リストに含めることができるオブジェクトの種類を示すゲートのようなものと考えてください。この継承とキャストのため、期待どおりに動作しません。あなたが示した例では、オレンジとリンゴの両方を に入れることができましたList<Fruit>。リストにリンゴとオレンジの両方が含まれている場合、どうすればそれを にキャストできますかList<Orange>

が必要な場合はList<Orange>List<Fruit>. とにかく明示的にキャストしていて、何が含まれているかを正確に知っている場合は、おそらく不必要な抽象化です。

変更できないAPIを使用しているが、その内容が正確にわかっている場合は、APIが必要なときに各Fruitインスタンスを確実かつ明示的にキャストするために、instanceofチェックをループスルーする必要があります。OrangeOrange

于 2011-06-15T16:54:49.460 に答える
0

List をキャストし、各要素がinstanceof Orangeであるかどうかをテストし、テストの後に Oranges でキャストする必要があります。これが「ベストプラクティス」です。

于 2011-06-15T16:34:51.540 に答える
0

与えられた

List<Fruit> getFruits() {...}

タイプキャストはできません

List<Orange> oranges = (List<Orange>) getFruits();

型の消去により、実行時の getFruits の型はただの List になります。コンパイラーは、ダウンキャストを行うことさえできません (私は疑わしいので、答える前に Eclipse で試しました)。

リストに Fruit のサブクラスが含まれることをコンパイラに伝えることができます。その場合、メソッドでワイルドカードを使用する必要があります。

List<? extends Fruit> getFruits() {...}

その後、キャストが可能になりますが、型の安全性に関する警告が表示されます:

@SuppressWarnings("unchecked")
List<Orange> oranges = (List<Orange>) getFruits();

getFruits の実行時型List であることを考えると、ジェネリック型情報を破棄して、安全でない代入を使用できます。

@SuppressWarnings("unchecked")    
List<Orange> oranges = (List) getFruits();

より多くのシステムリソースが必要になりますが、意図を明確に示すので、よりエレガントな方法かもしれません:

List<Orange> oranges = Arrays.asList((Orange[])getFruits().toArray())

Java の配列は実行時に型情報を保持するため、キャストは有効であり、コンパイラの観点からは "安全" ですが、フルーツ バスケットにいくつかのリンゴを渡すと、実行時例外がスローされる可能性があります。

于 2011-06-15T17:15:47.213 に答える