8

私のカスタム拡張ハッシュマップを考えてみましょう:

public class CustomHashMap extends HashMap<String, Object> {
...
}

CustomHashMap は HashMap の子であるため、これが機能しないのはなぜですか?

Map<String, HashMap<String, Object>> customs = new LinkedHashMap<String, CustomHashMap>();

しかし、これは機能します:

Map<String, HashMap<String, Object>> customs = new LinkedHashMap();

また、CustomHashMap をcustomsMap に追加 (配置) するときにも機能します。

customs.put("test", new CustomHashMap());

初期化時にジェネリックを指定しないとうまくいくのは奇妙に思えますが、それ以外の場合はそうではありません。

4

3 に答える 3

7

このステートメントは機能していません

Map<String, HashMap<String, Object>> customs = new LinkedHashMap<String, CustomHashMap>();

customsはタイプであり、は のサブクラスである タイプMap<String, HashMap<String, Object>>の を割り当てているためです。LinkedHashMap<String, CustomHashMap>CustomHashMapHashMap<String, Object>

ジェネリックスはinvariant次のとおりです。 任意の 2 つの異なる型T1およびはT2HashMap<String, T1>のサブタイプでもスーパータイプでもありませんHashMap<String, T2>。したがって、LinkedHashMap<String, CustomHashMap>に割り当てることはできませんMap<String, HashMap<String, Object>>。一方、配列は ですcovariant。これは、以下のステートメントがエラーや警告なしでコンパイルされることを意味します。HashMap<String, Object>ただし、 以外の のサブタイプをそれに入れると、実行時に失敗する可能性があります (これにより、さらに害が生じる可能性があります) CustomHashMap

HashMap<String, Object>[] mapArray = new CustomHashMap[1];
mapArray[0] = new CustomHashMap_1();// this will throw java.lang.ArrayStoreException

に代入LinkedHashMap<String, CustomHashMap>する場合Map<String, HashMap<String, Object>>は、ステートメントを次のように変更します。

Map<String, ? extends HashMap<String, Object>> customs = new LinkedHashMap<String, CustomHashMap>();

このアプローチに関するいくつかの追加情報は、@Seelenvirtuose によって適切に説明されており、これは受け入れられた回答です。

于 2013-11-14T11:44:25.203 に答える
4

ジェネリックを扱うときは、常に型の消去を念頭に置く必要があります。実行時に、型のオブジェクトはMapその型パラメーターを認識していません。結果: ALinkedHashMap<String, CustomHashMap>は のサブタイプではありませんMap<String, HashMap<String, Object>>

サブタイプに関連するものを持ちたい場合は、次の方法で行う必要があります。

Map<String, ? extends HashMap<String, Object>> customs = new LinkedHashMap<String, CustomHashMap>();

これは上限ワイルドカードと呼ばれ、まさにその場合のために存在します: サブタイプの関係を取得するため。詳細については、ジェネリックに関する Java チュートリアルを参照してください。


コメントによる追加情報:

上限版は税関地図の使い方にデメリットがあります。インスタンスをそのマップに配置することはできなくなりました。許可される唯一の値は ですnull。その理由は、別のクラスを拡張Map<String, HashMap>して、そのインスタンスをカスタムマップに入れようとする可能性があるためです。ただし、変数 customs は でパラメータ化されたマップを参照するため、これは問題CustomHashMapです。

限定されたワイルドカードを扱うときは、常にPECSを思い出してください。PECS とは、「生産者拡張、消費者スーパー」の略です。これは、メソッドのパラメーターにとって重要です。このようなマップから値を読み取るだけでよいメソッドを作成する場合は、パラメーターを のように入力できますMap<String, ? extends Map<String, Object>>。これをプロデューサーと呼びます。そのマップへの書き込みのみが必要な場合は、キーワードsuperを使用します。読み取りと書き込みの両方が必要な場合は、どちらも実行できません。

于 2013-11-14T11:48:29.483 に答える