Java - недоразумение HashMap о обработке столкновений и методе get()
Я использую HashMap
, и я не смог получить прямой ответ о том, как работает метод get()
в случае столкновений.
Скажем, n > 1
объекты помещаются в один и тот же ключ . Сохраняются ли они в LinkedList
? Они перезаписаны так, что существует только последний объект, помещенный в этот ключ? Используют ли они какой-то другой метод столкновений?
Если они помещены в LinkedList
, есть ли способ получить весь этот список? Если нет, есть ли какая-то другая встроенная карта для Java, в которой я могу это сделать?
Для моих целей отдельная цепочка была бы идеальной, как если бы были столкновения, мне нужно было бы просмотреть список и получить информацию обо всех объектах в нем. Каким будет лучший способ сделать это в Java?
Спасибо за вашу помощь!
Ответы
Ответ 1
Записываются ли они так, что там остается только последний объект, помещенный в этот ключ?
Да, если вы ставите несколько значений с одним и тем же ключом (согласно Object.equals
, а не Object.hashCode
.) Это указано в Map.put
javadoc:
Если ранее карта содержала отображение для ключа, старое значение заменяется указанным значением.
Если вы хотите сопоставить ключ с несколькими значениями, вам, вероятно, лучше использовать что-то вроде Guava ListMultimap
, ArrayListMultimap
в частности, который сопоставляет ключи спискам значений. (Disclosure: я вношу свой вклад в Guava.) Если вы не можете терпеть стороннюю библиотеку, то на самом деле вам нужно иметь Map<Key, List<Value>>
, хотя это может стать немного громоздким.
Ответ 2
В документации для Hashmap.put() четко указано: "Связывает указанное значение с указанным ключом на этой карте. Если на карте ранее содержалось отображение для ключа, старое значение заменено"
Если вы хотите иметь список объектов, связанных с ключом, сохраните список как значение.
Обратите внимание, что "столкновение" обычно относится к внутренней работе HashMap, где две клавиши имеют одно и то же значение хэша, а не использование одного и того же ключа для двух разных значений.
Ответ 3
Пусть скажем, что n > 1 объектов помещаются в один и тот же ключ. Сохраняются ли они в связанном списке? Они перезаписаны так, что существует только последний объект, помещенный в этот ключ? Используют ли они какой-то другой метод столкновений?
Для одного и того же ключа может быть один экземпляр, поэтому последний переопределяет предыдущий
Map<String, Integer> map = new HashMap<String, Integer>();
map.put("a", 1);
map.put("a", 2);// it overrides 1 and puts 2 there
цепочка появляется там, где для одного ключа используется один и тот же хэш
См
Ответ 4
Cite: "Пусть скажем, что n > 1 объектов помещаются в один и тот же ключ.Они хранятся в связанном списке? Они перезаписаны так, что там есть только последний объект, помещенный в этот ключ? Используют ли они какое-то другое столкновение метод?"
Да, если хэш файл содержит что-то под этим ключом, он переопределит его.
Вы можете реализовать свой собственный класс для обработки этого или более простого использования HashMap > где K - ваш ключевой объект и V - значение объекта.
Имейте в виду, что при последнем решении, когда вы выполните map.get(K), вы получите список или выбранную вами реализацию (например, ArrayList), чтобы все методы этой реализации были доступны вам и, возможно, соответствовали вашим требованиям. Например, если вы использовали Arraylist, у вас есть размер, trimToSize, removeRange и т.д.
Ответ 5
Разрешение конфликтов для хеширования в java не основано на цепочке. Насколько я понимаю, JDK использует двойное хеширование, которое является одним из лучших способов открытой адресации. Таким образом, список не будет связан с хеш-слотом.
Вы можете поместить объекты, для которых хеш-функция разрешается одному и тому же ключу, могут быть помещены в список, и этот список можно обновить в таблице/карте.
package hashing;
import java.util.HashMap;
import java.util.Map;
public class MainAnimal {
/**
* @param args
*/
public static void main(String[] args) {
Animal a1 = new Animal(1);
Animal a2 = new Animal(2);
Map<Animal, String> animalsMap = new HashMap<Animal, String>();
animalsMap.put(a1,"1");
animalsMap.put(a2,"2");
System.out.println(animalsMap.get(a1));
Map<String, Integer> map = new HashMap<String, Integer>();
map.put("a", 1);
map.put("a", 2);// it overrides 1 and puts 2 there
System.out.println(map.get("a"));
}
}
class Animal {
private int index = 0;
Animal(int index){
this.index = index;
}
public boolean equals(Object obj){
if(obj instanceof Animal) {
Animal animal = (Animal) obj;
if(animal.getIndex()==this.getIndex())
return true;
else
return false;
}
return false;
}
public int hashCode() {
return 0;
}
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
}
В приведенном выше коде мы показываем две разные вещи.
case 1 - два разных экземпляра, разрешающих одно и то же hashkey
case 2 - два одинаковых экземпляра, действующих как клавиши для двух разных записей.
Экземпляры животных, a1 и a2 разрешают один и тот же ключ. Но они не переоцениваются. Хеширующий механизм зондирует через хеш-слоты и помещает записи в разные слоты.
со вторым случаем, ключи решаются на один и тот же хэш-ключ, а также метод equals удовлетворяет. Следовательно, происходит переопределение.
Теперь, если в классе животных я переопределяю метод equals таким образом -
public boolean equals(Object obj){
// if(obj instanceof Animal) {
// Animal animal = (Animal) obj;
// if(animal.getIndex()==this.getIndex())
// return true;
// else
// return false;
// }
// return false;
return true;
}
Переключение происходит. Поведение похоже на использование одного и того же экземпляра. Так как a1 и a2 находятся в одном ведре и равны также true.