生の型パラメータでメソッドをオーバーライドするときに、未チェックの警告を回避できますか?
-
04-07-2019 - |
質問
変更できないライブラリで定義されているクラスを拡張しています:
public class Parent
{
public void init(Map properties) { ... }
}
Parentを拡張するクラス「Child」を定義し、ジェネリックでJava 6を使用している場合、未チェックの警告を表示せずにinitメソッドをオーバーライドする最良の方法は何ですか?
public class Child extends Parent
{
// warning: Map is a raw type. References to generic type Map<K,V> should be parameterized
public void init(Map properties) { }
}
汎用パラメーターを追加すると、次のようになります:
// error: The method init(Map<Object,Object>) of type Child has the same erasure as init(Map) of type Parent but does not override it
public void init(Map<Object,Object>) { ... }
// same error
public void init(Map<? extends Object,? extends Object>) { ... }
// same error
public void init(Map<?,?>) { ... }
このエラーは、特定のタイプ、境界付きワイルドカード、または境界なしワイルドカードを使用しているかどうかに関係なく発生します。警告なしで、@ SuppressWarnings(<!> quot; unchecked <!> quot;)を使用せずに、非汎用メソッドをオーバーライドする正しいまたは慣用的な方法はありますか?
解決
はい、ジェネリック情報を追加せずに、親クラスと同じシグネチャでオーバーライドメソッドを宣言する必要があります。
あなたの最善の策は、メソッドではなくraw-typeパラメーターに@SuppressWarnings("unchecked")
注釈を追加することだと思います。そのため、独自のコードにある可能性のある他のジェネリック警告を抑制しません。
他のヒント
簡単な答え:それを行う方法はありません。
満足できない答え:IDE / build.xmlで(特定の)警告を無効にします。
ライブラリを変更できない場合は、残念ながら、一般的でないメソッドを使用する必要があります。
問題は、型を消去した後、両方のinit()が同じシグネチャを持っているにもかかわらず、実際には異なるメソッドであるか、同じ(*)である可能性があることです。コンパイラーは、オーバーライドまたはオーバーロードすべきかどうかを判断できないため、禁止されています。
(*) ライブラリ開発者がinit(Map <!> lt; String、Integer <!> gt;)を意味すると仮定します。これで、init(Map <!> lt; String、String <!> gt;)を実装しています。これはオーバーロードであり、Childクラスのvtableに2つのメソッドが存在する必要があります。
しかし、ライブラリ開発者がinit(Map <!> lt; String、String <!> gt;)を意味する場合はどうでしょうか?その後、オーバーライドされ、メソッドはChildクラスの元のinitを置換する必要があり、Childのvtableにはメソッドが1つしかありません。
PS GenericsがJavaでどのように実装されているか嫌い:-(
上記の回答は、代わりに@SuppressWarnings(<!> quot; rawtypes <!> quot;)と言っていたと思います。
親と同じシグネチャでメソッドを宣言する必要があるため、コンパイル時に警告が表示されます。 @SuppressWarnings(<!> quot; unchecked <!> quot;)
でそれらを抑制することができますこれを取り除く方法がないのは、無効なタイプのコレクションを作成できることを警告する警告があるためです。警告は、それを許可する可能性のあるすべてのコードが削除された場合にのみ消えます。非ジェネリッククラスから継承しているため、無効なコンテンツを含むコレクションを作成することは常に可能です。