在java中使用hashcode()和equals()?

时间:2013-09-01 16:29:25

标签: java hash hashmap

这是我们用来放入hasmap的类。它已覆盖equals()hashcode()方法。

class Dog
    {
        public String name;
        public Dog(String n)
        {
            name=n;
        }
        @Override
        public int hashCode() {
            System.out.println("in hashcode");
            return name.length();
        }
        @Override
        public boolean equals(Object obj) {
            System.out.println("in equals");
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (getClass() != obj.getClass())
                return false;
            Dog other = (Dog) obj;
            if (name == null) {
                if (other.name != null)
                    return false;
            } else if (!name.equals(other.name))
                return false;
            return true;
        }


    }

此代码在主要

Map<Object,Object> m=new HashMap<Object,Object>();
        Dog d1=new Dog("clover");
        m.put(d1,"Dog Key");
        System.out.println(m.get(d1));

生成

in hashcode
in hashcode
Dog Key

但是以下代码为

Map<Object,Object> m=new HashMap<Object,Object>();
        Dog d1=new Dog("clover");
        m.put(d1,"Dog Key");
        System.out.println(m.get(new Dog("clover")));

产生

in hashcode
in hashcode
in equals
Dog Key

正如您所看到的,在第二个输出中调用了equals()方法。为什么会这样?
我的第二个问题
如果我更改密钥的name属性 Map m = new HashMap();

Dog d1=new Dog("clover");
        m.put(d1,"Dog Key");

        d1.name="arthur";
        System.out.println(m.get(new Dog("clover")));

o / p是

in hashcode
in hashcode
in equals
null

即使我更改了键值,但我试图通过提供相同的键来检索值。那么为什么它会检索null?

3 个答案:

答案 0 :(得分:3)

对于第一个问题:HashMap需要调用equals()来确认两个具有相同哈希码的Dog个对象实际上是相等的。它不需要第一次调用equals(),因为它使用==来检查使用与先前指定的完全相同的对象的特殊情况。

对于第二个问题:您更改了一个数据成员,该成员更改了哈希码的计算和equals()的结果。这是专门针对规则的,因此地图已损坏;在那一点上,任何事情都可能发生。永远不要将具有可变数据的对象用于HashMap

中的密钥

答案 1 :(得分:1)

这是因为在将d1=new Dog("clover")放入hashmap后,您将其名称更改为d1.name="arthur";,因此名称为arthur的Dog不再等于new Dog("clover")

因此,首先检查密钥哈希码,然后匹配,因为"clover".length等于"arthur".length,这样可以识别保存对象的存储桶。之后执行equals()检查以从存储桶中获取正确的对象,并且由于您的密钥不等于提供的密钥而失败。

实际上,使用可变字段进行哈希码计算并不是一个好习惯。

答案 2 :(得分:1)

让我们考虑一下HashMap的工作原理。

  1. 许多对象可以具有相同的hashCode。什么时候将对象放入映射中,它基于hashCode方法的结果构建表。 HashMap将具有相同hashCode的对象存储在列表中,并且每个这样的列表都附加到具有与特定hashCode相关联的单元的表。
  2. 何时从地图中获取对象,它会评估传递的关键对象的hashCode,然后获取与给定hashCode关联的对象列表。然后它使用equals方法在列表中查找对象。
  3. 使用正确的哈希码算法和HashMap的容量设置允许在put上达到O(1)性能并获得通常。

    现在让我们考虑一下你的问题:

    1. 你去,然后从hashMap获取。你会看到一个“in equals”语句,因为你有一个不同的密钥对象。当键相同时会有一些优化,在这种情况下HasMap不会调用equals方法。在第一种情况下,d1 == d1,但是d1!=第二种新狗(“三叶草”)。
    2. 您的对象具有相同的hashCode,但它们不再相等。和钥匙是不同的
    3. 但是如果你改变你的代码:

      Dog d1=new Dog("clover");
          m.put(d1,"Dog Key");
      
          d1.name="arthur";
          System.out.println(m.get(d1));
      

      它应该最终给你一个。