1

这是我们将用来放入 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;
        }


    }

这段代码在 main

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()在第二个输出中有对方法的调用。为什么呢?
我的第二个问题
如果我更改键 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?

4

3 回答 3

3

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

对于第二个问题:您更改了一个数据成员,该成员更改了哈希码的计算和equals(). 这是特别违反规则的,因此地图被破坏了;到那时,任何事情都可能发生。永远不要使用具有可变数据的对象作为 a 中的键HashMap

于 2013-09-01T16:40:01.787 回答
1

这是因为在你放入d1=new Dog("clover")hashmap 之后,你改变了它的名字,d1.name="arthur";所以 Dog with namearthur不再等于new Dog("clover").

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

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

于 2013-09-01T16:39:44.163 回答
1

让我们考虑一下 HashMap 是如何工作的。

  1. 许多对象可以具有相同的 hashCode。当您将对象放入地图时,它会根据 hashCode 方法的结果构建一个表。HashMap 将具有相同 hashCode 的对象存储在一个列表中,并且每个这样的列表都附加到表中,其中一个单元格与特定的 hashCode 相关联。
  2. 何时从映射中获取对象时,它会评估传递的键对象的 hashCode,然后获取与给定 hashCode 关联的对象列表。然后它使用 equals 方法在列表中查找对象。

为 HashMap 使用适当的哈希码算法和容量设置通常可以在 put 和 get 上达到 O(1) 性能。

现在让我们考虑您的问题:

  1. 你去 put 然后从 hashMap 中获取。您会看到“in equals”语句,因为您有不同的 key 对象。当键相同时有一些优化,在这种情况下 HasMap 不会调用 equals 方法。在第一种情况下 d1 == d1,但 d1 != new Dog("clover") 用于第二种情况。
  2. 您的对象具有相同的 hashCode,但它们不再相等。而且钥匙不一样

但是,如果您在此更改代码:

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

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

最后它应该给你atrhur。

于 2013-09-01T17:10:59.007 回答