Java - 关于碰撞处理和get()方法的HashMap混淆

时间:2012-10-18 01:39:09

标签: java hashmap

我正在使用HashMap而我无法直接回答get()方法在碰撞情况下的工作原理。

假设n > 1个对象放在同一个中。它们存储在LinkedList中吗?它们是否被覆盖,以便只存在那个键中的最后一个对象?他们正在使用其他一些碰撞方法吗?

如果将它们放在LinkedList中,有没有办法检索整个列表?如果没有,是否有其他内置的 Java 地图,我可以在其中执行此操作?

就我的目的而言,单独的链接是理想的,就好像存在冲突一样,我需要能够查看列表并获取有关其中所有对象的信息。在 Java 中执行此操作的最佳方法是什么?

感谢您的帮助!

5 个答案:

答案 0 :(得分:8)

documentation for Hashmap.put()明确指出,“将指定的值与此地图中的指定键相关联。如果地图以前包含该键的映射,则旧值将被替换”< / p>

如果您想要一个与密钥关联的对象列表,请将列表存储为值。

请注意,'collision'通常是指HashMap的内部工作,其中两个键具有相同的哈希值,而不是对两个不同的值使用相同的键。

答案 1 :(得分:7)

  

它们是否被覆盖,以便只存在该键中的最后一个对象?

是的,假设您使用相同的密钥放置多个值(根据Object.equals,而不是Object.hashCode。)Map.put javadoc中指定的值:

  

如果地图以前包含该键的映射,则旧值将替换为指定的值。

如果你想将一个键映射到多个值,你可能最好使用像Guava的ListMultimapArrayListMultimap这样的东西,它将键映射到值列表。 (披露:我向Guava捐款。)如果你不能容忍第三方库,那么你真的需要Map<Key, List<Value>>,尽管这可能有点笨拙。

答案 2 :(得分:3)

  

假设n&gt; 1个对象放在同一个键中。它们是否存储在链表中?它们是否被覆盖,以便只存在那个键中的最后一个对象?他们正在使用其他一些碰撞方法吗?

同一个密钥可能有单个实例,因此最后一个覆盖前一个

Map<String, Integer> map = new HashMap<String, Integer>();
map.put("a", 1);
map.put("a", 2);// it overrides 1 and puts 2 there

链接来自不同键的相同哈希值


查看

答案 3 :(得分:0)

引用:“假设n&gt; 1个对象放在同一个键中。它们是否存储在链表中?它们是否被覆盖,以便只存在该键中的最后一个对象?它们是否正在使用其他对象?碰撞方法?“

是的,如果hashmap包含此键下的内容,它将覆盖它。

您可以实现自己的类来处理或更简单地使用HashMap&gt;其中K是您的关键对象,V是对象值。 请记住,当您执行map.get(K)时,使用最后一个解决方案将检索List或您选择的实现(即:ArrayList),以便您可以使用此实现的所有方法,并且可能满足您的要求。例如,如果你使用了Arraylist,你就有了size,trimToSize,removeRange等等。

答案 4 :(得分:0)

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;
    }


}

在上面的代码中,我展示了两个不同的东西。

案例1 - 两个不同的实例解析为相同的hashkey 情况2 - 两个相同的实例充当两个不同条目的键。

动物实例,a1&amp; 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。