Ошибка несовместимых типов при попытке создать карту карт
Я пытаюсь создать карту карт, используя ConcurrentSkipListMap
, Если я создам простой пример карты, это будет хорошо:
Map<Integer, Integer> mmap2 = new ConcurrentSkipListMap<Integer, Integer>();
Как только я пытаюсь создать карту карт, я получаю Incompatible types
ошибка:
Map<Integer, Map<Integer, Integer>> mmap =
new ConcurrentSkipListMap<Integer, ConcurrentSkipListMap<Integer, Integer>>();
Если я переключу определение, чтобы включить ConcurrentSkipListMap
, его компилируется без проблем:
Map<Integer, ConcurrentSkipListMap<Integer, Integer>> mmap =
new ConcurrentSkipListMap<Integer, ConcurrentSkipListMap<Integer, Integer>>();
Почему я не могу определить карту карты, используя Map
интерфейс?
4 ответа
Я могу ответить на вопрос с примером.
Map<Integer, Map<Integer, Integer> mmap = new ConcurrentSkipListMap<Integer, ConcurrentSkipListMap<Integer, Integer>>();
mmap.put(5, new HashMap<Integer, Integer>());
В этом случае ожидаете ли вы, что линия пут будет разрешена? Если это не разрешено, то это нарушает определение mmap. Если это разрешено, то оно ломает правую сторону.
Вы создали строку кода, которая, работает ли она или нет, дает вам противоречие. Поэтому мы не допускаем таких определений mmap.
Наследование не распространяется на Generics type parameters
,
Вы можете использовать подстановочные знаки, как показано ниже.
Map<Integer, ? extends Map<Integer, Integer>> mmap = new ConcurrentSkipListMap<Integer, ConcurrentSkipListMap<Integer, Integer>>();
Больше информации читайте java подтип
Концепция чего-либо 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
универсальный тип и не будет выдавать ошибок; потому что, какой тип является допустимым, а какой нет, неизвестно во время выполнения. Но, если вы скажете: "Эй, это то, что я хочу! Square
идти в списке Shape
s. " Затем определите список, используя new ArrayList<Shape>()
и компилятор будет соответствовать.
Итак, вам просто нужно сделать свое назначение как
Map<Integer, Map<Integer, Integer>> mmap =
new ConcurrentSkipListMap<Integer, Map<Integer, Integer>>();
то есть, предпочитая использование интерфейсов, согласованных с обеих сторон, при использовании обобщений.
РЕДАКТИРОВАТЬ: (В ответ на downvote @PaulBellora)
Есть причина, почему вы можете назначить Circle[]
в Shape[]
но нет ArrayList<Circle>
в ArrayList<Shape>
, И причина в том, что если ваш код пытается добавить Square
к Circle[]
через Shape[]
ссылка, вы бы получили ArrayStoreException
во время выполнения, потому что JVM будет знать фактический тип массива.
Но из-за стирания типов та же безопасность типов во время выполнения не может быть распространена на коллекции, и, следовательно, универсальные типы не являются ко-вариантами. Если вопрос заключался в том, почему этот тип был стерт, то знание его во время выполнения может иметь определенные преимущества; Ответ будет хорошо играть с базой кода до Java 5.
Вы можете попробовать это здесь, у вас будет ссылка на карту внутри объекта карты
public class GenericTest {
void fun(){
Map<Integer, Map<Integer, Integer>> mmap = new HashMap<Integer, Map<Integer, Integer>>();
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
mmap.put(5,map);
}
}