2013-07-08 2 views
5

У меня есть вопрос относительно дженериков:Detail о «супер» шаблона в Java дженериков

Map<? super String, ? super String> mappa1 = new HashMap<Object,Object>(); 

с супер, что можно создать экземпляр HashMap<Object,Object> для <? super String>. Однако тогда вы можете добавить только объекты, которые расширяют String (в этом случае только сама строка). Почему они не запрещают ошибку компиляции, а также с шаблоном extends. Я имею в виду, если однажды созданный Map <Object, Object> можно только добавить Strings .. почему бы не заставить создать Map<String, String> в первую очередь? (например, с шаблоном extends)

Снова я знаю разницу между super и extends относительно дженериков. Я хотел бы просто узнать подробности, о которых я упомянул.

Заранее спасибо.

+1

Однако тогда вы можете добавить только те объекты, на которые распространяются строка (в данном случае только сам String) Вы можете добавить CharSequences и объект, а не OBJETS которые распространяются String. – Nimajen

+0

@ Нимажен упоминается в вопросе. – Rollerball

+0

извините, не тот ключ. Мой комментарий был неполным. – Nimajen

ответ

2
Map<? super String, ? super String> mappa1 = new HashMap<Object,Object>(); 

Поскольку Java дженериков основаны на типа стирания, с этой линией вы не создали MashMap<Object,Object>. Вы только что создали экземпляр класса HashMap; параметры типа теряются сразу после этой строки кода, и все, что остается, является типом вашей переменной mappa1, которая даже не упоминает Object. Тип выражения new является совместимым с назначением с типом mappa1, поэтому компилятор допускает назначение.

В общем, параметры типа используются с new не имеют никакого отношения, и для решения этой проблемы, Java 7 уже ввел оператор алмазную<>. Все, что действительно имеет значение, это тип mappa1, который составляет Map<? super String, ? super String>; что касается остальной части вашего кода, это тип созданной копии.

+0

http://docs.oracle.com/javase/tutorial/java/generics/erasure.html Однако в этой ссылке говорится: <Заменить все параметры типа в родовых типах своими границами или объектом, если параметры типа неограничены. Таким образом, полученный байт-код содержит только обычные классы, интерфейсы и методы.> – Rollerball

+0

Кроме того, в случае шаблона «extends» также должно быть разрешено. Intead невозможно создать HashMap , если ссылка Map <. – Rollerball

+0

Конечно, это не так: 'Object' не расширяет' String'. –

0

Проблема, которую вы описываете, не существует. Это потому, что ваша ссылка объявлена ​​как Map<? super String, ? super String>. Но ваш реальный объект может содержать любой объект, так как это HashMap<Object,Object>

Map<? super String, ? super String> mappa1 = new HashMap<Object,Object>(); 
map1.put("", ""); 

//you can put only string to map1 

//but you can do this 
Map map2 = map1; 
map2.put(23, 234); 

то же самое может быть описана более удачный пример:

String a = "a". 
a.length(); // legal. 

Object b = a; 
b.length() // compilation error 
+0

Это не отвечает на мой вопрос. Я не хочу знать обходное решение для этого. Я хотел бы просто знать, почему это так работает – Rollerball

+1

Извините, это не обходное решение, это объяснение. Строка - это обычный класс на Java. Компилятору все равно, является ли ваш пользовательский класс или java.lang.String. – Tala

2

Я думаю, вы отброшены, потому что выбрали тип коллекции. Коллекции редко используются в качестве потребителей, и поэтому нижняя граница (? super X) не ставится на их типы элементов. Более подходящим примером является предикат.

Рассмотрите способ, например <E> List<E> filter(List<? extends E> p, Predicate<? super E> p). Он примет список l и предикат p и вернет новый список, содержащий все элементы l, которые удовлетворяют p.

Вы можете отправить List<Integer> и Predicate<Number>, которые удовлетворяют все краткие оценки 2.5. Predicate<Number> станет Predicate<? super Integer>. Если это не так, вы не можете вызвать фильтр следующим образом.

List<Integer> x = filter(Arrays.asList(1,5,8,10), Predicates.multipleOf(2.5)); 
5

Давайте использовать List вместо Map для краткости.

По существу, практический смысл extends и super может быть определена следующим образом:

  • List<? extends T> означает "List вы можете получить T от"
  • List<? super T> означает "List вы можете положить T в"

Теперь вы можете видеть, что нет ничего особенного в отношении extends - поведение extends и super полностью симметрично:

List<? extends Object> a = new ArrayList<String>(); // Valid, you can get an Object from List<String> 
List<? extends String> b = new ArrayList<Object>(); // Invalid, there is no guarantee that List<Object> contains only Strings 

List<? super String> a = new ArrayList<Object>(); // Valid, you can put a String into List<Object> 
List<? super Object> b = new ArrayList<String>(); // Invalid, you cannot put arbitrary Object into List<String> 
Смежные вопросы