如果hashcode返回一个常量值,则在HashSet.contains()的情况下调用hashCode()和equals()的次数

时间:2015-05-07 11:36:11

标签: java hashcode

我已阅读过Java文档页面,但我无法解释为什么hashCode()equals()的来电次数会有这样的变化?

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class NumberOfCalls {
    int field;

    public int getField() {
        return field;
    }

    public NumberOfCalls(int field) {
        this.field = field;
    }

    @Override
    public int hashCode() {
        System.out.println("In Hashcode method.");
        return 10;
    }

    @Override
    public boolean equals(Object obj) {
        System.out.println("In Equals Method");
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        NumberOfCalls other = (NumberOfCalls) obj;
        if (field != other.field)
            return false;
        return true;
    }

    public static void main(String[] args) {
        NumberOfCalls object1 = new NumberOfCalls(5);
        NumberOfCalls object2 = new NumberOfCalls(6);
        NumberOfCalls object3 = new NumberOfCalls(5);
        Set<NumberOfCalls> set = new HashSet<NumberOfCalls>();
        set.add(object1);
        set.add(object2);
        Iterator<NumberOfCalls> it = set.iterator();
        System.out.print("Size of set is : " + set.size()
            + "\nObject fields values present in set are : ");
        while (it.hasNext()) {
            System.out.print(it.next().getField() + "   ");
        }
        System.out.println("\n---------------------------------------------------");
        System.out.println("Now checking number of calls -- ");
        System.out.println("Object1 is present in set ? - " + set.contains(object1)+"\n");
        System.out.println("Object2 is present in set ? - " + set.contains(object2)+"\n");
        System.out.println("Object3 is present in set ? - " + set.contains(object3)+"\n");
    }
}

上述代码的输出为

  

在Hashcode方法中。
  在Hashcode方法中。
  在等于方法中   套装尺寸为:2
  集合中存在的对象字段值为:6 5

     

----------------------------------------------- ----
  现在检查通话次数 -
  在Hashcode方法中。
  在等于方法中   对象1出现在集合中? - 的真实

     

在Hashcode方法中。
  对象2出现在集合中? - 的真实

     

在Hashcode方法中。
  在等于方法中   在等于方法中   对象3出现在集合中? - 的真实

问题:

  1. hashCode()equals()object1而非object2(在这种情况下仅调用hashCode())时,为什么会一次调用?{ / LI>
  2. 为什么在equals()
  3. 的情况下调用object3两次

1 个答案:

答案 0 :(得分:7)

当您向Set添加元素时,它会存储在Map内部,其中key是您传入的对象,value设置为null。内部Map维护链表的数组(存储桶)。这些阵列也可称为存储桶。使用hashCode()方法评估存储桶的索引。

在你的情况下,因为hashCode()返回一个常量值,所以放入Set的所有值都将放在同一个桶中。因此,对于第一次调用set.add(object1),内部结构将类似于

  

bucket [object1 - &gt;空]

由于每个存储桶都包含一个链表,因此存储在列表中的元素具有指向下一个元素的指针。由于只有一个元素添加到列表中,因此指针指向null

对于下一个电话set.add(object2),数据结构将如下所示

  

bucket [object2 - &gt; object1 - &gt;空]

现在,只要您拨打set.contains(some_object),就会调用hashCode()来找出正确的存储桶。此调用还返回对第一个元素的引用。

回答第一个问题:

因此,当您致电set.contains(object2)时,它实际上会返回对object2的引用。现在,如果你看一下HashMap班级&#39;代码首先使用==运算符比较此引用是否与传入的引用相同。因为在这种情况下它是相同的,所以它不会调用equals()方法。以下是HashMap类的代码段:

if (e.hash == hash &&
                ((k = e.key) == key || (key != null && key.equals(k))))
                return e;

这应该解释你的第一个问题。

回答第二个问题:

当您致电set.contains(object3)时,会计算存储桶索引并返回对object2的引用。现在object2 == object3返回false,因此Map调用object3.equals(object2)方法(首次调用equals()方法)来检查两个对象是否有意义相等。这也返回false,因此它遍历列表并返回对列表中下一个元素的引用,即object1

再次object1 == object3返回false,因此Map调用object3.equals(object1)(第二次调用equals()方法)方法来检查两个对象是否有意义等效。

这会导致2次调用equals()方法。