Я бы порекомендовал вам посмотреть документацию об универсальных c подстановочных знаках особенно рекомендации по использованию подстановочных знаков
Откровенно говоря, ваш метод # didntCompile
static void doesntCompile(Map<Integer, List<? extends Number>> map) {}
и вызов как
doesntCompile(new HashMap<Integer, List<Integer>>());
В корне неверно
Давайте добавим допустимая реализация:
static void doesntCompile(Map<Integer, List<? extends Number>> map) {
List<Double> list = new ArrayList<>();
list.add(0.);
map.put(0, list);
}
Это действительно хорошо, потому что Double расширяет Number, так что выражение List<Double>
абсолютно нормально, также как и List<Integer>
, верно?
Однако вы все еще думаете, что это Legal передать здесь new HashMap<Integer, List<Integer>>()
из вашего примера?
Компилятор так не считает, и делает все возможное, чтобы избежать таких ситуаций.
Попробуйте сделайте ту же реализацию с методом #compile, и компилятор, очевидно, не позволит вам поместить список двойников в карту.
static <T extends Number> void compiles(Map<Integer, List<T>> map) {
List<Double> list = new ArrayList<>();
list.add(10.);
map.put(10, list); // does not compile
}
В принципе, вы можете положить только 1038 *, поэтому безопасно вызывать этот метод с new HashMap<Integer, List<Integer>>()
или new HashMap<Integer, List<Double>>()
или new HashMap<Integer, List<Long>>()
или new HashMap<Integer, List<Number>>()
.
Итак, в двух словах, вы пытаетесь обмануть с помощью компилятора, и он справедливо защищает от такого обмана.
Примечание: ответ от Мориса Перри абсолютно верный. Я просто не уверен, что это достаточно ясно, поэтому попытался (очень надеюсь, что мне удалось) добавить более обширный пост.