#java #generics #java_hashmap #hashmap
Почему метод put принимает на вход key параметр типа K:
public V put(K key, V value)
а метод get принимает на вход key параметр типа Object?
public V get(Object key)
Я пробовала в своей упрощённой реализации HashMap использовать методы
public V get(K key)
public V put(K key, V value)
и это работает, точно так же, как работает и
public V get(Object key)
public V put(Object key, Object value)
Насколько я понимаю, метод put должен принимать именно K key и V value, потому что
в теле этого метода вызывается метод
void addEntry(int hash, K key, V value, int bucketIndex)
и без явного приведения типов (addEntry(hash, (K) key, (V) value, i);) вызов этого
метода вызвал бы ошибку компиляции, если бы key и value были бы типа Object. Но почему
метод get принимает на вход key параметр типа Object, а не K? Ведь это же как-то некрасиво,
что ли (разный стиль)... и в этом должен быть, наверное, какой-то особый смысл.
Ответы
Ответ 1
Оргиниал ответа
Всё дело в том, что спецификация Map не требует того, чтобы все ключи имели одинаковый
тип. Она лишь требует корректного поведения метода equals (и hashCode для HashMap)
для объектов, которые используются в качестве ключей.
Конечно реализация метода equals обычно требует, чтобы совпадали, в том числе, классы
сравниваемых объектов. Но есть случаи, где имеется другое поведение. К примеру при
сравнении реализаций java.util.List (ArrayList, LinkedList и т.д.) требуется лишь,
чтобы было эквивалентно именно содержимое этих списков. По указанной причине вы можете
объявить переменную с типом Map при этом в метод get передавать
переменную типа LinkedList и это будет вполне рабочий вариант.
Если же задаваться вопросом зачем объявлять Map вместо Map, то я могу привести, хоть и узконаправленный, но всё же пример. Представьте,
что ваша переменная с типом Map периодически сериализуется, и вам
очень важно быстродействие указанной сериализации. Поэтому вы требуете явно, чтобы
записываемые ключи был именно указанного типа (я сейчас не буду говорить о реальной
скорости сериализации ArrayList). А при поиске объекта-значения в метод get вы можете
передавать аргумент любого типа, к примеру тот же LinkedList, что немного упростит
вам жизнь.
P.S. На эту тему можно конечно подискутировать, но таковы реалии Java. Вполне возможно,
что это недостаток проектирования. И ссылаясь на этот ответ могу сказать, что пытались
сделать нечто подобное, но возникли некоторые трудности, и от этой идеи отказались.