5

私のプロジェクトには、次のようなコードがあります。

public interface Bar<T extends Foo<?>> {
 //...
}

public class MyFoo implements Foo<String> {
    private List<Bar<Foo<String>> barFoo = ...

    public <U extends Foo<String>> boolean addBar(Bar<? extends U> b) {
        barFoo.add((Bar<Foo<String>>) b); //safe cast?
    }

}

Eclipse はaddBar、キャストが安全ではないという警告を出します。ただし、型パラメーターに課した制限を考慮してキャストがスローされないため、キャストは実際に安全であると想定するのは正しいですか?

4

3 に答える 3

6

一般的ではありません。

メソッドBarvoid get(T value)あり、 と の 2 つの実装がFoo<String>あるMyFooとしYourFooます。次に、呼び出し元がaddBartype の値を呼び出すとしますBar<MyFoo>。これは機能します: U=Foo<String>の場合、それBar<MyFoo>は のサブタイプですBar<? extends U>。次に、その値を にキャストしますBar<Foo<String>>

を引数としてBar受け入れるメソッドがない場合でも、問題はありません。Tしかし、メソッドがあるとしますvoid process(T value)。呼び出した実装にはT=があるため、メソッドMyFooしかありません。process(MyFoo value)ただし、これを a にキャストするBar<Foo<String>>と、代わりに a で呼び出すことができますYourFoo。これは違法です。

暗闇で突き刺しますが、あなたが本当にやりたかったbarFooのはList<? extends Bar<? extends Foo<String>>.

于 2013-02-13T22:06:57.907 に答える
2

これは安全なキャストではありません。エクリプスは正しいです。

MyFoo拡張するクラスがあり、署名のみがコンパイルされたときに署名付きのメソッドFooを渡したと想像してください。そのため、メソッドの検索は失敗します。Bar<MyFoo<String>>BarmyMethod(Foo x)myMethod(MyFoo x)

于 2013-02-13T22:00:27.173 に答える
0

キャストは安全ではありませんU。なぜならextendsはありますが、 (必ずしも) extendsの場合Foo<String>ではないからです。実際、はそれらが同じものである場合、つまり が である場合にのみ拡張されます。Bar<U>Bar<Foo<String>>Bar<U>Bar<Foo<String>>UFoo<String>

直観的には、(たとえば)List<String>は のサブタイプであるべきだと思われるかもしれList<Object>ませんが、これはジェネリックの仕組みではありません。List<String>は のサブタイプですが、 のサブタイプではList<? extends Object>ありませんList<Object>。(次のような例を検討する方がより理にかなっているかもしれませんComparable<T>。 :Comparable<String>は " を any と比較できることを意味するStringのに対して、 " は any と比較できることを意味します。が のサブタイプであってはならないことは明らかです。)Comparable<Object>ObjectComparable<String>Comparable<Object>

[…]キャストは[…]をスローしないため、キャストは本当に安全ですか?

警告の性質を誤解していると思います。Eclipse は、このキャストはスローすべきときにもスローしないことを警告しています。これが、実際には安全ではない理由です。たとえば、次のコード:

final Object o = Integer.valueOf(7);
final String s = (String) o;

キャストは例外をスローするため、完全に安全です。しかし、このコード:

final List<?> wildcardList = new ArrayList<Integer>(Integer.valueOf(7));
final List<String> stringList = (List<String>) wildcardList;

unsafestringListです。これは、ランタイムが (消去のために) キャストをチェックする方法がないためです。したがって、間違っていても例外はスローされませList<String>Integer。(何が起こるかというと、後で、ClassCastExceptionその要素で何かをしようとすると自発的に取得できるということです。)

于 2013-02-13T22:08:20.460 に答える