2010-12-08 23 views
20

次のコードがあります:java:チェックされていないキャスト警告を修正する方法

private HashMap<Class<?>, HashMap<Entity, ? extends Component>> m_componentStores; 

public <T extends Component> T getComponent(Entity e, Class<T> exampleClass) 
{ 
    HashMap<Entity, ? extends Component> store = m_componentStores.get(exampleClass); 

    T result = (T)store.get(e); 

    if (result == null) 
    { 
     throw new IllegalArgumentException("GET FAIL: "+e+" does not possess Component of class\nmissing: "+exampleClass); 
    } 

    return result; 
} 

コンパイルすると、T result = (T)store.get(e)にチェックされていないキャストがあることが示されます。

Type safety: Unchecked cast from capture#2-of ? extends Component to T 

この警告が表示されないようにするには、何が欠けていますか?

答えて

32

Class.castです。さて、あなたは反射を使わないと考えるかもしれません。

変更行:

T result = (T)store.get(e); 

へ:キャスト文の上記

T result = exampleClass.cast(store.get(e)); 
+0

+1、常により良いでClassCastExceptionが維持しますライブラリコードIMO。ライブラリが型ミスをしていないことを証明することができれば、厳密には必要ではありません(つまり、 'setComponent'は適切かつ対称的に機能します)。次に、警告を抑止します。 –

+3

@ Mark Petersプログラマーが自信を持っているほとんどの問題では、通常は間違っています。 –

+1

私はそれがすべての図書館のデザイナーに当てはまるとは思っていません。もしそうなら、図書館を書くべきではありません。 APIに未チェックのキャストの例があります。 'Collections.emptyList()'が思い浮かびます。 –

14

書き込み@SuppressWarnings("unchecked")

@SuppressWarnings("unchecked") 
T result = (T)store.get(e); 

そして、無視しても安全である理由の説明文を追加警告。

+0

無視するのは安全ではありません。簡単な例を考えてみましょう: 'abstract class Animal {public abstract void makeNoice(); } '、' class CatはAnimal {} 'を継承し、' class DogはAnimal {} 'を継承します。 「犬」と「猫」はどちらも「動物」です(彼らは確かです)。今すぐ: 'class SomeAnimalUtils {public static void makeNoise(動物動物){犬犬=(犬)動物; dog.makeNoice(); }} '。両方が正しくメソッドを実装しているとしましょう。 'SomeAnimalUtils.makeNoise()'は、 'Animal'を拡張するので' Cat'を取るこ​​とができますが、 'Dog'にキャストすることはできず、' ClassCastException'をキャッチします。 – Roland

+0

まあ、私の例はここに愚かですが、実際にはチェックされていないキャストを処理する必要があることを示す必要があります。 'Cat'を' Dog'( 'Terrier'や' Husky'のような他のクラスのスーパークラスかもしれません)の 'Cat'に入れないようにするためです。しかし、誰かが意図しない' Cat'をJVMで投げた場合、例外がスローされます。 'SomeAnimalUtils'のプログラマがパラメータをチェックせず、hilfselfによって例外をスローしたことを意味するので、これは悪いことです。 – Roland

+0

これを事前にチェックする必要があります。そのようにするには、安全でない/チェックされていないキャストの前に次のコードを追加します: 'if(null == animal){throw new NullPointerException("パラメータ 'animal'がnull '); ( "animal '=" + animal.toString()+ "Dogのインスタンスではありません"); } '。ここでは、Java言語が「オブジェクト化された」パラメータ(=オブジェクトまたは任意のインタフェースのインスタンス)として渡すことができるヌル参照チェックも処理しなければなりません。ヌル参照を考慮しない場合は、ここで悪名高いNPEを危険にさらす可能性があります。 – Roland

3

ジェネリックスでは実際にはそのようには機能しません。 T!= ? extends ComponentT extends Componentでもあなたが持っているものは実際にはwildcard captureですが、それは別の目的を持っています。

そして、はい、あなたのソリューションは、タイプセーフではありません - 2 ?マークの間には関係がではありません。

private HashMap<Class<?>, HashMap<Entity, ? extends Component>> m_componentStores; 

だから、いくつかを使用して、この構造ではComponentのいくつかのサブクラスのインスタンスを置くために法的になり他のクラス(Componentのサブクラスでもない)をキーとして使用します。

m_componentStoresはそのことextendsComponent以外のあなたがそこに持っている価値、どのようなタイプを正確に知る方法がない実行時のように、一般的なタイプは、唯一コンパイル時で解決されることに注意してください。

ですから、store.get(e)から入手タイプは... Componentです:あなたはTComponentを唱えたとき、キャストを静的にチェックすることができないため

Component result = store.get(e); 

、コンパイラは警告を発行します。しかし、データ構造のセマンティクスが確実であれば、単に警告を抑制することができます。

@SuppressWarnings("unchecked") 
    T resultT = (T)result; 

PS: あなたはワイルドカードキャプチャを必要としない、次のことがあなたのケースでまったく同じに動作します:

private HashMap<Class<?>, HashMap<Entity, Component>> m_componentStores; 
関連する問題