Недавно от товарища пришел вопрос на засыпку: "Почему в интерфейсe java.util.Map метод get в качестве ключа принимает Object, а метод put использует женерики?"
V get(Object key); V put(K key, V value);
Сходу ответить не смог, пришлось разбираться.
Сразу пришло на ум несколько гипотез:
- раздолбайство
- легаси-код
- "так специально задумано"
Не смотря на то, что первые две гипотезы вполне правдоподобны, думаю самый интересный это третий вариант ("так специально задумано"). Если поискать в интернете,то можно найти следующее объяснение.
По "контракту", который был еще в версиях до женериков, Map должен работать с ключами по следующему правилу:
key==null ? k==null : key.equals(k)
Легко видеть, что т.к. в при вызове метода key.equals(k) объекты key и k потенциально могут быть абсолютно разных классов, то в итоге мы не имеем право вводить ограничение на тип в сигнатуре метода.
Конечно большинство java-программистов знают, что если нужно переопределить метод equals, то по хорошему надо сделать проверку типа проверяемого объекта, но в жизни всякое случается...
В качестве примера к объяснению, в интернете можно встретить пример на списках.
Суть очень простая. Мы предполагаем, что списки равны тогда, когда равны все их элементы. При этом по большому счету не так уж и важно какой именно это список (ArrayList, LinkedList и т.д.).
В итоге если использовать список в качестве ключа, то возникнет следующая (вполне реальная) ситуация.
Map<LinkedList, Integer> m = new HashMap<LinkedList, Integer>(); LinkedList a = new LinkedList(); a.add("1"); a.add("2"); m.put(a, a.size()); // конечно здесь мы явно создаем ArrayList, // но впринципе нам может вернуться какой-то непонятный список // из какого-то непонятного метода: // например List b = doVeryStrangeMethod(); List b = new ArrayList(a); // Этот вызов метода нормально компилируется и вернет результат: System.out.println(m.get(b)); // А вот этот вызов приведет к ошибке компиляции, т.к. put с generic-ом // m.put(b, b.size());
P.S.: Лично я в жизни не сталкивался с ситуацией, когда нужно было использовать список в качестве ключа.
■
