◆== 用于比较两个内存的地址 ◆equals,用于比较两个对象的值 ◆hashCode用于在Hash集合中快速定位对象

为什们使用hashcode()

Java中的集合有两类,一类是List,再有一类是Set。前者集合内的元素是有序的,元素可以重复;后者元素无序,但元素不可重复。 equals方法可用于保证元素不重复,但如果每增加一个元素就检查一次,若集合中现在已经有1000个元素,那么第1001个元素加入集合时,就要调用1000次equals方法。这显然会大大降低效率。 于是,Java采用了哈希表的原理。

哈希算法也称为散列算法,是将数据依特定算法直接指定到一个地址上。这样一来,当集合要添加新的元素时,先调用这个元素的HashCode方法,就一下子能定位到它应该放置的物理位置上。

(1)如果这个位置上没有元素,它就可以直接存储在这个位置上,不用再进行任何比较了;

(2)如果这个位置上已经有元素了,就调用它的equals方法与新元素进行比较,相同的话就不存了;

(3)不相同的话,也就是发生了Hash key相同导致冲突的情况,那么就在这个Hash key的地方产生一个链表,将所有产生相同HashCode的对象放到这个单链表上去,串在一起。这样一来实际调用equals方法的次数就大大降低了,几乎只需要一两次。

  • 是用来比较两个对象的地址是否相等,即是否是同一个对象。equals()是用来比较两个对象的内容是否相等,即是否具有相同的属性值。如果没有重写equals()方法,那么它默认就是用 来比较。
  • hashcode()是用来返回一个对象在Java虚拟机中的地址,也就是散列值。散列值可以用来加快查找和比较的速度,例如在哈希表中。
  • equals()相等的两个对象,hashcode()一定相等;但equals()不相等的两个对象,却并不能证明他们的hashcode()不相等。因为不同的对象可能有相同的散列值,这就是哈希冲突。

3.hashcode

有了equals方法为啥还需要hashcode,这是一个很好的问题。equals方法可以判断两个对象是否相等,但是它的效率不高,因为它需要逐个比较对象的属性。hashcode方法可以提高查找的效率,因为它只需要比较一个整数值。如果两个对象的hashcode不同,那么它们一定不相等,就不用再调用equals方法了。如果两个对象的hashcode相同,那么它们可能相等,也可能不相等,这时候才需要调用equals方法来进一步判断。

重写hashcode和equals

重写equals和hashcode的代码,根据¹,一般来说,我们需要遵循以下原则:

  • 如果两个对象相等(equals方法返回true),那么它们的hashcode必须相等。
  • 如果两个对象不相等(equals方法返回false),那么它们的hashcode可以相等,也可以不相等。
  • 如果两个对象的hashcode相等,那么它们可能相等,也可能不相等。
  • 如果两个对象的hashcode不相等,那么它们一定不相等。

重写equals方法时,我们需要考虑以下几点:

  • equals方法必须是自反的、对称的、传递的和一致的²。
  • equals方法必须接受一个Object类型的参数,并且判断参数是否为null或者是否与当前对象属于同一个类。
  • equals方法必须比较当前对象和参数对象的所有关键属性,并且如果所有属性都相同,则返回true,否则返回false。

重写hashcode方法时,我们需要考虑以下几点:

  • hashcode方法必须与equals方法保持一致,即如果两个对象相等,则它们的hashcode必须相等;如果两个对象不相等,则它们的hashcode可以不相等³⁴。
  • hashcode方法应该尽量避免冲突,即尽量让不同的对象产生不同的hash值。
  • hashcode方法应该尽量简单高效,以提高性能。

下面是一个重写equals和hashcode方法的例子:

public class Person {
    private String name;
    private int age;
 
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
 
    // 重写equals方法
    @Override
    public boolean equals(Object obj) {
        // 判断是否为null
        if (obj == null) {
            return false;
        }
        // 判断是否为同一个对象
        if (this == obj) {
            return true;
        }
        // 判断是否属于同一个类
        if (this.getClass() != obj.getClass()) {
            return false;
        }
        // 强制转换为Person类型
        Person person = (Person) obj;
        // 比较name和age属性
        return this.name.equals(person.name) && this.age == person.age;
    }
 
    // 重写hashCode方法
    @Override
    public int hashCode() {
        // 使用31作为乘数,因为它是一个奇素数,可以减少冲突的概率
        int result = 31;
        // 使用name和age属性计算hash值
        result = result * 31 + name.hashCode();
        result = result * 31 + age;
        return result;
    }
}

源: 与必应的对话, 2023/3/9(1) 重写equals、hashCode,及Lombok中关于@Data的使用. https://blog.csdn.net/weixin_44094122/article/details/105267955 访问时间 2023/3/9. (2) Java equals() and hashCode() Contracts | Baeldung. https://www.baeldung.com/java-equals-hashcode-contracts 访问时间 2023/3/9. (3) 理解Java中equals()和hashcode()的关系 - 知乎. https://zhuanlan.zhihu.com/p/347342971 访问时间 2023/3/9. (4) 重写equals()&hashCode()&toString()—Java类设计_黯叶的博客-CSDN博客. https://blog.csdn.net/qq_40780805/article/details/99771771 访问时间 2023/3/9.