の概念はPolymorphism、クラスと同じように Java ジェネリックには適用されません。そのため、ConcurrentSkipListMap<Integer, ConcurrentSkipListMap<Integer, Integer>>は のサブタイプと見なされMap<Integer, Map<Integer, Integer>>ず、割り当てられません。
これは、ジェネリックがコンパイル時のタイプセーフのみを提供するためです。型消去と呼ばれるものが原因で、実行時にジェネリック型は不明です。したがって、基本的にコンパイラはこれを防ごうとしています
// if this was allowed
List<Shape> shapes = new ArrayList<Circle>();
// and some place else in your code
shapes.add(new Square()); // Square now fits in a Circle list
ArrayListこれはのジェネリック型を破壊し、エラーをスローしません。どの型が有効で、どの型が有効でないかは、実行時にはわからないためです。しかし、「ねえ、それが私がしたいことです! s のSquareリストに入りたい」と言ったら。Shape次に、使用するnew ArrayList<Shape>()とコンパイラが準拠するようにリストを定義します。
したがって、次のように割り当てを行う必要があります
Map<Integer, Map<Integer, Integer>> mmap =
new ConcurrentSkipListMap<Integer, Map<Integer, Integer>>();
つまり、ジェネリックを使用しながら、両側で一貫したインターフェイスを使用することを好みます。
編集:(@PaulBelloraの反対票に応じて)
Circle[]に を割り当てられるのに に割り当てられShape[]ないのArrayList<Circle>には理由がありますArrayList<Shape>。その理由は、コードが参照を介して aSquareに aを追加しようとすると、JVM が配列の実際の型を認識しているため、実行時に が取得されるためです。Circle[]Shape[]ArrayStoreException
ただし、型の消去により、同じランタイム型の安全性をコレクションに拡張することはできません。したがって、ジェネリック型は共変ではありません。問題がなぜタイプを消去したのかということだった場合、実行時にそれを知っていると明らかにメリットがあるかどうか。答えは、Java 5 より前のコード ベースをうまく利用することです。