POJOを次のように指定しています。MyClass<U>
ここU
で、は汎用型パラメーターです。クラス参照を受け入れ、Class<T>
タイプのマップにデータを入力するMap<String, T>
(データを入力するマップを受け入れる)ユーティリティメソッドを作成しようとしています。
このメソッドは次のように実装されます。
static void populateMap(Map<String, T> map, Class<T> type) {
...
// Parses into the specified type and returns an object of that type.
T obj = parse(..., type);
map.put (key, obj);
...
return map;
}
これは正常にコンパイルされます。呼び出し元ではMyClass
、値として(タイプに関係なく)任意のインスタンスをマップに入力しようとしています。したがって、次のコードを使用します。
// Loses type information
Map<String, MyClass<?>> m = new HashMap<>();
populateMap(m, MyClass.class);
これはコンパイルされません。コンパイルエラー:
populate(Map<String,T>, Class<T>)
タイプ...のメソッドは引数には適用できません(Map<String,MyClass<?>>, Class<MyClass>)
どうすればこれを修正できますか?
この場合、チェックされていないキャストをClass<MyClass<?>>
次のように実行しても安全です。
// This is okay because we're switching to a type with an unbounded wildcard -
// the behaviors of Class.newInstance and Class.cast are still safe.
@SuppressWarnings("unchecked")
Class<MyClass<?>> classWithNarrowedType =
(Class<MyClass<?>>)(Class<?>)MyClass.class;
populateMap(m, classWithNarrowedType);
これは、特にこのような呼び出しサイトが多数ある場合は、厄介な解決策ですが、クラスリテラルが生の型でパラメータ化され、MyClass<T>
本質的に厄介なパラメータ化された型のファクトリとして使用されるという事実を回避することはできません。
潜在的にクリーンなソリューションはpopulateMap
、クラスリテラルの使用から切り離されます。
interface Parser<T> {
T parse();
}
static void populateMap(Map<String, T> map, Parser<T> parser) { ... }
...
Map<String, MyClass<?>> m = new HashMap<>();
Parser<MyClass<?>> myClassParser = new Parser<MyClass<?>>() {
@Override
public MyClass<?> parse() {
return parse(..., MyClass.class);
}
};
populateMap(m, myClassParser);
余談ですが、より柔軟な署名をお勧めします(詳細については、PECS(Producer Extends Consumer Super)とは何ですか?を参照してください)。
static void populateMap(Map<String, ? super T> map, Parser<T> parser)
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加