У меня была такая же ошибка при настройке eclipse.ini для использования JRE6. Оказывается, я вызвал эту ошибку, неправильно настроив eclipse на использование 64-разрядной JVM при запуске 32-разрядной версии eclipse 3.7.
Правильная настройка требовала, чтобы в eclipse.ini -vm argumument использовался «C: / Program Files (x86) /» вместо «C: / Program Files /».
Сделать убедитесь, что используемая версия JVM (32/64 бит) соответствует версии eclipse (32/64 бит).
Как упоминалось другими, причина, по которой get()
и т. д. не является общей, потому что ключ для записи, которую вы извлекаете, не должен быть того же типа, что и объект, который вы передаете get()
; спецификация метода требует только того, чтобы они были равны. Это следует из того, как метод equals()
принимает параметр Object as, а не только тот же тип, что и объект.
Хотя может быть общепринято, что многие классы имеют equals()
так, чтобы его объекты может быть только равным объектам своего класса, на Java есть много мест, где это не так. Например, в спецификации List.equals()
указано, что два объекта List равны, если они оба являются списками и имеют одно и то же содержимое, даже если они являются разными реализациями List
. Поэтому, возвращаясь к примеру в этом вопросе, согласно спецификации метода возможно иметь Map<ArrayList, Something>
и для меня, чтобы вызвать get()
с аргументом LinkedList
как, и он должен получить ключ, который является список с тем же содержимым. Это было бы невозможно, если get()
были родовыми и ограничивали свой тип аргумента.
Обратная совместимость, я думаю. Map
(или HashMap
) по-прежнему необходимо поддерживать get(Object)
.
put
(что ограничивает общие типы). Вы получаете обратную совместимость, используя необработанные типы. Дженерики - это «отказ».
– Thilo
1 September 2011 в 11:02
Причина в том, что сдерживание определяется equals
и hashCode
, которые являются методами на Object
, и оба принимают параметр Object
. Это был ранний недостаток дизайна в стандартных библиотеках Java.
Единственный способ иметь безопасные хеш-таблицы и равенство в Java - это избегать Object.equals
и Object.hashCode
и использовать общий заменитель. Функциональная Java поставляется с типами классов только для этой цели: Hash<A>
и Equal<A>
. Предоставляется оболочка для HashMap<K, V>
, которая принимает Hash<K>
и Equal<K>
в своем конструкторе. Таким образом, методы get
и contains
этого класса принимают общий аргумент типа K
.
Пример:
HashMap<String, Integer> h =
new HashMap<String, Integer>(Equal.stringEqual, Hash.stringHash);
h.add("one", 1);
h.get("one"); // All good
h.get(Integer.valueOf(1)); // Compiler error
Контракт выражается следующим образом:
Более формально, если эта карта содержит отображение из ключа k в значение v, такое что (ключ == null? k == null: key .equals (k)), то этот метод возвращает v; в противном случае он возвращает null. (Это может быть не более одного такого отображения.)
blockquote>(мой акцент)
и как таковой успешный поиск ключей зависит от реализации ключа ввода метод. Это не обязательно , зависящее от класса k.
hashCode()
. Без правильной реализации hashCode () хорошо выполненный equals()
в этом случае бесполезен.
– rudolfson
13 May 2009 в 12:51
get()
не нужно брать аргумент типа Object
, чтобы удовлетворить контакт. Представьте, что метод get был ограничен типом ключа K
- контракт все равно был бы действительным. Конечно, использование, когда тип времени компиляции не был подклассом K
, теперь не скомпилировался, но это не аннулирует контракт, поскольку контракты неявно обсуждают, что происходит, если код компилируется.
– BeeOnRope
2 June 2016 в 23:09
Это применение закона Postel's, «быть консервативным в том, что вы делаете, быть либеральным в том, что вы принимаете от других».
Проверки равенства могут выполняться независимо от типа ; метод equals
определен в классе Object
и принимает любой параметр Object
в качестве параметра. Таким образом, имеет смысл эквивалентность ключей и операции, основанные на эквивалентности ключей, для принятия любого типа Object
.
Когда карта возвращает значения ключа, она сохраняет как можно больше информации о типе, используя ее параметр типа.
V Get(K k)
в C #, потому что это также имеет смысл. Разница между подходами Java и .NET - это только тот, кто блокирует несоответствующие вещи. В C # это компилятор, в Java это коллекция. Я рвусь о несовместимых классах коллекции .NET время от времени, но Get()
и Remove()
, принимающие только подходящий тип, конечно, не позволяют вам случайно передать неправильное значение.
– Wormbo
29 May 2012 в 12:33
Сейчас мы делаем большой рефакторинг, и нам не хватало этого строго типизированного get (), чтобы проверить, что мы не пропустили какой-то get () со старым типом.
Но я нашел обходной / уродливый трюк для проверка времени компиляции: создать интерфейс карты с строго типизированным get, containsKey, удалить ... и поместить его в пакет java.util вашего проекта.
Вы получите ошибки компиляции только для вызова get (),. .. с неправильными типами, все остальные выглядят нормально для компилятора (по крайней мере внутри eclipse kepler).
Не забудьте удалить этот интерфейс после проверки вашей сборки, поскольку это не то, что вы хотите во время выполнения.
Существует еще одна веская причина: это невозможно сделать технически, потому что оно вызывает карту.
Java имеет полиморфную общую конструкцию, такую как <? extends SomeClass>
. Помеченная такая ссылка может указывать на тип, подписанный с помощью <AnySubclassOfSomeClass>
. Но полиморфный родословный делает эту ссылку только для чтения. Компилятор позволяет использовать общие типы только как возвращающий тип метода (например, простые геттеры), но блокирует использование методов, когда общий тип является аргументом (например, обычные сеттеры). Это означает, что если вы пишете Map<? extends KeyType, ValueType>
, компилятор не позволяет вам вызывать метод get(<? extends KeyType>)
, и карта будет бесполезной. Единственное решение - сделать этот метод не общим: get(Object)
.
Удивительный Java-кодер в Google, Кевин Бурриллион, писал об этой проблеме в блоге некоторое время назад (по общему признанию, в контексте Set
вместо Map
). Наиболее релевантное предложение:
Равномерно методы Framework Java Collections Framework (и библиотеки коллекций Google) никогда не ограничивают типы их параметров, кроме случаев, когда необходимо предотвратить сбои коллекции.
Я не совсем уверен, что согласен с ним в принципе: .NET, похоже, требует правильного типа ключа, например - но стоит ли рассуждать в блоге , (Обозначив .NET, стоит пояснить, что часть причины, по которой это не проблема в .NET, заключается в том, что проблема с больше в .NET имеет более ограниченную дисперсию ...)
Integer
и Double
никогда не могут быть равны друг другу, все равно остается справедливым вопрос о том, содержит ли Set<? extends Number>
значение new Integer(5)
.
– Kevin Bourrillion
19 June 2012 в 16:10
Set<? extends Foo>
. Я очень часто менял тип ключа карты, а затем был разочарован тем, что компилятор не смог найти все места, где необходимо было обновить код. Я действительно не уверен, что это правильный компромисс.
– Porculus
21 September 2012 в 21:52
Совместимость.
До того, как появились дженерики, было только что (Object o).
Если бы они изменили этот метод, чтобы получить (& lt; K> o), он будет иметь потенциально принудительное массовое обслуживание кода для пользователей java, чтобы снова скомпилировать рабочий код.
Они могли ввели дополнительный метод , например get_checked (& lt; K> o) и обесценить старый метод get (), чтобы существовал более мягкий путь перехода. Но почему-то это не было сделано. (Ситуация, в которой мы сейчас находимся, заключается в том, что вам необходимо установить такие инструменты, как findBugs, для проверки совместимости типов между аргументом get () и объявленным типом ключа & lt; K> на карте.)
Аргументы Я думаю, что использование семантики .equals () является фиктивным. (Технически они верны, но я все еще думаю, что они фиктивные. Ни один дизайнер в здравом уме никогда не сделает o1.equals (o2) истинным, если o1 и o2 не имеют общего суперкласса.)
Я смотрел на это и думал, почему они это сделали. Я не думаю, что какие-либо из существующих ответов объясняют, почему они не могли просто заставить новый общий интерфейс принять только правильный тип для ключа. Фактическая причина заключается в том, что, хотя они и вводили дженерики, они НЕ создавали новый интерфейс. Интерфейс карты - это тот же самый старый универсальный Map, который просто служит как универсальной, так и не универсальной версией. Таким образом, если у вас есть метод, который принимает не общие карты, вы можете передать ему Map<String, Customer>
, и он все равно будет работать. В то же время контракт на получение принимает объект, поэтому новый интерфейс также должен поддерживать этот контракт.
По моему мнению, они должны были добавить новый интерфейс и реализовать как на существующую коллекцию, но они решили в пользу совместимости интерфейсов, даже если это означает худший дизайн для метода get. Обратите внимание, что сами коллекции будут совместимы с существующими методами, только интерфейсы не будут.
Я думаю, что в этом разделе учебника Generics объясняется ситуация (мой акцент):
«Вам нужно убедиться, что общий API не является чрезмерно ограничительным, он должен продолжаться для поддержки первоначального контракта API. Рассмотрим еще несколько примеров из java.util.Collection. Пред-общий API выглядит так:
interface Collection {
public boolean containsAll(Collection c);
...
}
Наивная попытка его генерировать:
interface Collection<E> {
public boolean containsAll(Collection<E> c);
...
}
Хотя это, безусловно, безопасный тип, он не соответствует оригинальному контракту API. Метод containsAll () работает с любым входящим набором. Он будет успешным только в том случае, если входящая коллекция действительно содержит только экземпляры из E, но:
containsAll( Collection< ? extends E > c )
, тогда?
– Judge Mental
30 April 2013 в 00:20
containsAll
с Collection<S>
, где S
является супертипом i> E
. Это было бы недопустимо, если бы это было containsAll( Collection< ? extends E > c )
. Кроме того, поскольку is i> явно указано в примере, законно передавать коллекцию другого типа (с возвращаемым значением, а затем false
).
– davmac
10 June 2014 в 13:13
V Get(K k)
в C #? – user 14 September 2011 в 16:21m.get(linkedList)
, почему вы не определили типm
какMap<List,Something>
? Я не могу думать о том, что вызыватьm.get(HappensToBeEqual)
, не меняя типMap
, чтобы получить интерфейс, имеет смысл. – Elazar Leibovich 14 February 2012 в 14:07