Несовместимые типы подстановочных знаков, которые должны быть совместимы
Исходя из этого вопроса, который предоставляет решение, но не объясняет его (к сожалению, ссылки в ответах сейчас мертвы):
Возьмите следующий метод:
void method(Map<?, ?> myMap) {
Set<Map.Entry<?, ?>> set = myMap.entrySet();
...
}
Просто нет? Однако, это не в состоянии скомпилировать на jdk1.7.0_25:
incompatible types required: java.util.Set<java.util.Map.Entry<?,?>> found: java.util.Set<java.util.Map.Entry<capture#1 of ?,capture#2 of ?>>
WTF? Map.entrySet()
указывается как возвращающий объект типа Set<Map.Entry<K, V>>
так что в приведенном выше примере, myMap.entrySet()
возвращает Set<Map.Entry<?, ?>>
, Но это не компилируется!
Еще более странно, из связанного вопроса наверху, изменение метода на это делает его компиляцией:
void method(Map<?, ?> myMap) {
Set<? extends Map.Entry<?, ?>> set = myMap.entrySet();
...
}
WTF??? призвание entrySet
на Map<?, ?>
возвращает Set<Map.Entry<K, V>>
, который нельзя присвоить переменной типа Set<Map.Entry<K, V>>
, но это может к переменной типа Set<? extends Map.Entry<K, V>>
?????
Кто-нибудь может пролить свет на то, что здесь происходит? И значит ли это, что всякий раз, когда я пишу метод, использующий подстановочный тип, по крайней мере, на 2 уровня, я должен помнить, чтобы сделать это ? extends ...
где-то?
1 ответ
Каждый из тех? может варьироваться независимо, поэтому нет гарантии, что <?,?>
в декларации myMap
соответствует <?,?>
в декларации set
,
Что это означает, что когда-то у меня есть Set<Map<?,?>>
Я могу поставить любой тип Map
в этот набор, потому что Map<?,?>
это супертип всех типов Map
, Но это не свойство, которое Set<Map<String,Integer>>
(например) имеет - это намного более ограничительно с точки зрения того, какие типы карт я могу поместить в него. Так Set<Map<?,?>>
не супертип Set<Map<String,Integer>>
, Но myMap.entrySet()
может быть легко Set<Map<String,Integer>>
в зависимости от того, что myMap
является. Таким образом, компилятор должен запретить нам присваивать его переменной типа Set<Map<?,?>>
и вот что происходит.
С другой стороны, Set<? extends Map<?,?>>
это супертип Set<Map<String,Integer>>
, так как Map<String,Integer>
это подтип Map<?,?>
, Так что можно назначить myMap.entrySet()
к переменной типа Set<? extends Map<?,?>>
,
Обратите внимание, что в этом нет ничего особенного String
а также Integer
здесь, но myMap
должна быть карта чего-то!
Вы могли бы написать
<K, V> void method(Map<K, V> myMap) {
Set<Map.Entry<K, V>> set = myMap.entrySet();
...