Вопрос-ответ

What are the reasons why Map.get(Object key) is not (fully) generic

По каким причинам Map.get (ключ объекта) не является (полностью) универсальным

Каковы причины, стоящие за решением не использовать полностью универсальный метод get в интерфейсе java.util.Map<K, V>.

Чтобы прояснить вопрос, сигнатура метода

V get(Object key)

вместо

V get(K key)

и мне интересно, почему (то же самое для remove, containsKey, containsValue).

Переведено автоматически
Ответ 1

Как упоминалось другими, причина, по которой get() и т.д., не является общей, потому что ключ извлекаемой записи не обязательно должен быть того же типа, что и объект, которому вы передаете get(); спецификация метода требует только, чтобы они были равны. Это следует из того, что equals() метод принимает объект в качестве параметра, а не только тот же тип, что и объект.

Хотя обычно может быть правдой, что многие классы equals() определены так, что его объекты могут быть равны только объектам его собственного класса, в Java есть много мест, где это не так. Например, в спецификации для List.equals() говорится, что два объекта списка равны, если они оба являются списками и имеют одинаковое содержимое, даже если они являются разными реализациями List. Итак, возвращаясь к примеру в этом вопросе, в соответствии со спецификацией метода возможно иметь Map<ArrayList, Something> и для меня вызывать get() с LinkedList в качестве аргумента, и он должен извлекать ключ, который представляет собой список с тем же содержимым. Это было бы невозможно, если бы get() был универсальным и ограничивал его тип аргумента.

Ответ 2

Потрясающий Java-программист из Google, Кевин Бурриллион, некоторое время назад написал именно об этой проблеме в сообщении в блоге (по общему признанию, в контексте Set вместо Map). Наиболее релевантное предложение:


Единообразно методы Java Collections Framework (и библиотека Google Collections тоже) никогда не ограничивают типы своих параметров, за исключением случаев, когда это необходимо для предотвращения взлома коллекции.


Я не совсем уверен, что согласен с этим в принципе - например, .NET, кажется, подходит для использования правильного типа ключа, но стоит следовать рассуждениям в сообщении в блоге. (Упомянув .NET, стоит объяснить, что одна из причин, по которой это не проблема в .NET, заключается в том, что в .NET существует большая проблема с более ограниченными вариациями ...)

Ответ 3

Контракт выражается таким образом:


Более формально, если эта карта содержит отображение из ключа k в значение v такое, что (ключ ==null ? k==null : ключ.равно(k)), тогда этот метод возвращает v; в противном случае он возвращает null. (Может быть не более одного такого сопоставления.)


(мой акцент)

и как таковой, успешный поиск ключа зависит от реализации метода равенства с помощью входного ключа. Это не обязательно зависит от класса k.

Ответ 4

Это применение закона Постеля, "будь консервативен в том, что ты делаешь, будь либеральен в том, что ты принимаешь от других".

Проверки на равенство могут выполняться независимо от типа; equals метод определен в Object классе и принимает любой Object в качестве параметра. Итак, для эквивалентности ключей и операций, основанных на эквивалентности ключей, имеет смысл принимать любой Object тип.

Когда map возвращает значения ключей, он сохраняет как можно больше информации о типе, используя параметр type .

2023-11-19 14:53 java generics collections