当前位置: 首页 > 面试题库 >

为什么在添加到HashSet和hashCode匹配项时未调用equals()?

越雨泽
2023-03-14
问题内容

当我运行此代码时,为什么我的实现对两个条目都生成相同的代码,为什么不只hashCode()调用equals方法呢?hashCode()``hashCode``HashSet

import java.util.HashSet;

public class Test1 {
    public static void main(String[] args) {
        Student st=new Student(89);
        HashSet st1=new HashSet();
        st1.add(st);
        st1.add(st);
        System.out.println("Ho size="+st1.size());
    }
}
class Student{
    private int name;
    private int ID;
    public Student(int iD) {
        super();
        this.ID = iD;
    }
    @Override
    public int hashCode() {
        System.out.println("Hello-hashcode");
        return ID;
    }
    @Override
    public boolean equals(Object obj) {
        System.out.println("Hello-equals");
        if(obj instanceof Student){
            if(this.ID==((Student)obj).ID){
                return true;
            }
            else{
                return false;
            }
        }
        return false;  
    }
}

输出为:

Hello-hashcode
Hello-hashcode
Ho size=1

问题答案:

哈希集首先检查引用相等性,如果通过,则跳过该.equals调用。这是一个优化和工作,因为合同equals,如果指定a == b然后a.equals(b)

我在下面附加了源代码,并突出显示了此检查。

相反,如果添加两个不相同引用的相等元素,则会获得预期的效果:

    HashSet st1=new HashSet();
    st1.add(new Student(89));
    st1.add(new Student(89));
    System.out.println("Ho size="+st1.size());

结果是

$ java Test1
Hello-hashcode
Hello-hashcode
Hello-equals
Ho size=1

这是来自OpenJDK 7的源代码,其中指明了相等性优化(来自HashMap的基础实现HashMap):

public V put(K key, V value) {
    if (key == null)
        return putForNullKey(value);
    int hash = hash(key.hashCode());
    int i = indexFor(hash, table.length);
    for (Entry<K,V> e = table[i]; e != null; e = e.next) {
        Object k;
//                                         v-- HERE
        if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
            V oldValue = e.value;
            e.value = value;
            e.recordAccess(this);
            return oldValue;
        }
    }

    modCount++;
    addEntry(hash, key, value, i);
    return null;
}


 类似资料:
  • 下面是产生散列集大小为3而不是2的代码 您可以看到这两个对象在输出中具有相同的代码,但被计算为不同的,并且产生的代码被计算为3 请协助我如何工作。

  • 我的任务是实现一个蛮力算法来输出一些n的整数[1,2,…, n]的所有排列。但是,我似乎在将ArrayList对象添加到HashSet时遇到了一些问题: 我发现对“nextPer的连续调用确实找到了所有排列,但是我不明白当我将排列添加到HashSet“allPer的排列”时会发生什么。我在n=3的情况下运行时得到的输出是这样的: [[3, 2, 1, 1, 2, 1, 1, 3, 1, 2], [

  • 问题内容: 例如,当我们向窗格添加新按钮时,我们需要编写以下代码: 为什么我们需要调用“ getChildren()”?它甚至做什么?我们为什么不能说: 我们将按钮添加到窗格中。我们不会将其添加到其子项中, 问题答案: 简短的答案就是“您必须那样做,因为这就是API的编写方式”。当然,您可能真正要问的是为什么要这样编写API。我认为这实际上是两个(相关的)问题。一种与方法名称有关,以及该方法的作用

  • 问题内容: 决定将这些方法包含在java.lang.Object中的背后原因是什么?平等和哈希对于许多类没有意义。 建立两个接口将更加合乎逻辑: 例如,HashSet定义可能看起来像 这将防止出现一个常见的初学者错误-使用项目集而不实现equals / hashCode。 问题答案: 当我们实现一个接口时,我们注入(或接受)该接口定义的合同。 &是两个不同的合同。但是,如果我们仔细观察,就会发现它

  • 问题内容: 据我了解,默认容量为10,并且当其超过10时,它将创建具有新容量的新对象,依此类推。 因此,出于好奇,我输入下面的程序来检查的对象: 根据上述情况,当我未将默认初始容量设置为10时,因此在添加第11个元素时,它将创建一个新对象并增加的容量。 当我打印对象的哈希码时,每次都会给出一个新值。 以下是o / p: 根据默认容量的概念,直到第10个元素之前,都应打印相同的内容,因为在此之前不需

  • 我试图使用Java以编程方式从XSD文件生成JAXB类。我使用以下代码片段来实现这一点: 生成的类只包含字段的方法。但是,我还希望包括、和方法。如何在生成代码时做到这一点?