2013-12-24 4 views

ответ

4

? в воспроизведенных (в Java земле) означает, что он может быть заменен на любой тип (этот тип необязательно может быть ограничен.) В случае воспроизведенных, Objectне может безопасно быть заменен на любой тип таким образом (он сталкивается с проблемой generics and subtyping, потому что дженерики стираются во время выполнения.)

Таким образом, эти два семантически идентичны, как вы могли бы ожидать, следовательно, ошибка компиляции.

В качестве примера того, что может пойти не так, если бы это было разрешено, вы могли бы сделать:

Map<String, ?> value = new HashMap<String, String>(); 
Map<String, Object> val = value; //This line would fail in real life, but assuming it passes... 
val.put("Hello", 0); //We could do this! 

... который явно не имеет никакого смысла - HashMap имеет тип <String, String> пока вы имеете поставьте Integer!

Это где ? представление отличается - вы не могли ничего, кроме Object в карте поместить, не вызывая ошибку компиляции:

value.put("Hello", 0); //Error 

Стоит отметить, что массивы не несут те же ограничения, так как они являются reified и, таким образом, могут вызывать значимые исключения во время выполнения, когда возникает несоответствие типа. (Является ли это предпочтительным, это вопрос дебатов, но лично я предпочитаю ловить ошибки раньше времени компиляции!) Поскольку generics не могут этого сделать, компилятор должен обеспечить их безопасность во время компиляции.

+2

Великого объяснение для старого ошибочного мнения, что дженерик не КОВАРИАНТНЫХ из-за типа стирания кроме - компилировать проверки времени всегда предпочтительнее во время выполнения проверки. –

0

No. Map<String, Object> не супертип Map<String, ?>, так что назначение не типобезопасное.

(Тем не менее, Map<String, ?>является супертипа всех Map<String, T>. Так противоположность коды бы работы.)

0

Оба Map<String, ?> и Map<String, Object> потенциально может принимать любые Object в качестве значения. Насколько вы знаете в своем коде, который наиболее определен, вы можете предположить. (относится к .get(key))

Но заполнитель ? означает, что он может быть другого конкретного типа.

E.g. Map<String, ?> разрешено быть Map<String, Apple> во время выполнения. И вы не можете назначать дженерики разных типов друг другу. Даже когда есть только теоретический шанс, что у вас может быть карта яблок.

0

Нет, это capture of, и это вызывает ошибку компиляции, потому что, очевидно, ? не просто означает объект ...Однако, это то, что вы, кажется, хотите -

Map<String, Object> value;     // I get an Object 
Map<String, ? extends Object> val = value; // Something that is an Object. 

или даже

Map<String, Object> value; 
Map<String, ?> val = value;    // Will take anything... 
              // Object is more specific. 
0

с шаблонного связанного ?, вы сообщаете компилятору, что вы не знаете, и не важно, что общий тип. Это нормально, если вы только читаете из контейнера и используете методы, объявленные на верхней границе (например, вы можете читать с Collection<?> и звонить toString() или List<? extends Closeable> и звонить по телефону close()), но небезопасно размещать объекты в сборку (на самом деле это может быть Collection<URL>, и попытка добавить String может испортить его).

1

Я идиот и оставляю это здесь для моего позора.

Covariance and contravariance with generic types in c# является распространенным источником путаницы. Это было своеобразным (не то, что оно было разбито как таковое) в .NET 4, но новый способ создания типовых типов работает так, как вы описываете, - это отказаться, а не с обратной стороны.

+1

Однако этот вопрос касается Java ... –

+0

Ha! Так что, это. Это то, что я получаю для stackoverflow на моем iPhone во время питья. –

+0

+1 для редактирования;) – berry120

-2
Map<String, ?> value = null; // initialize 
    Map<String, Object> val = (Map<String, Object>) value; //cast 
Смежные вопросы