为什么重写equals()方法时必须重写hashCode()方法【详解】

目录

一、为什么重写equals()方法时必须重写hashCode()方法

1、关于hashCode()的约定

hashCode()方法源码注释:

2、equals()方法和hashCode()方法的关系

3、为什么一定要使用 hashcode() 方法

举例说明:

4、HashMap结构

参考文章:

HashMap结构图:

5、重写hashcode()方法演示

代码演示:

运行结果:


一、为什么重写equals()方法时必须重写hashCode()方法

1、关于hashCode()的约定

hashCode()方法源码注释:

If two objects are equal according to the {@code equals(Object)}
method, then calling the {@code hashCode} method on each of
the two objects must produce the same integer result.

意思就是:如果两个对象根据equals()方法比较是相等的,那么调用这两个对象的hashcode()方法也必须产生相同的结果;

 

2、equals()方法和hashCode()方法的关系

  • 如果两个对象相同(即:用 equals 比较返回true),那么它们的 hashCode 值一定要相同;

  • 如果两个对象的 hashCode 值相同,但是它们并不一定相同(即:用 equals 比较返回 false);

 

3、为什么一定要使用 hashcode() 方法

根本原因是为了提升程序运行效率

hashCode()方法返回一个hashCode值,实际上就是一个int整数;

hashCode值的作用是确定该对象在哈希表中的索引位置;

根据上面equals()和hashCode()的关系,我们在比较两个对象是否相同的时候可以先比较他们的hashCode值,如果hashCode值不同的话就没有必要再使用equals()进行比较了,因为使用equals()进行比较本身就是一个低效率的过程;

举例说明:

我们都知道list集合是有序的,可以重复,set集合是无序的,不可以重复,那么怎么保证放入的元素不重复呢?仅仅使用equals()方法是不可能的,比如要存放第10001个元素,难道要与前面10000个元素挨个equals()比较吗?这效率太低了,因此hashCode就应运而生了!Java就采用了哈希表,利用哈斯算法(也叫散列算法),将对象数据根据其特征使用特定的算法将其定义到一个地址上,那么在后面存放进来的数据只需要首先判断对应的地址是否有数据,如果有就先比较它们的hashCode是否相等,如果相等就再使用equals()比较内容是否相同,反之直接插入,(同样,比较两个对象是否相同,也可以先比较两个对象的hashCode是否相等,如果相等再进行equals()比较,反之直接返回false即可)这样就大大减少了使用equals()的次数,提升了程序运行效率

简而言之,重写hashcode()方法的目的就是:保证使用equals()方法比较相同的对象,所对应的hashCode值也相同的;

 

4、HashMap结构

参考文章:

复习一波HashMap底层实现原理解析https://blog.csdn.net/qq_37840993/article/details/108048597

HashMap结构:数组 + 链表(或红黑树(JDK8开始),当链表长度超过8,就会转成红黑树,以提高查询效率);

HashMap结构图:

 

5、重写hashcode()方法演示

代码演示:

package com.zibo.java.february.second;

public class MyEquals {
    public static void main(String[] args) {
        Student s1 = new Student("訾博", 24);
        Student s2 = new Student("訾博", 24);
        System.out.println(s1.equals(s2)); // true
        System.out.println(s1.hashCode());
        System.out.println(s2.hashCode());
    }
}
class Student{
    private String name;
    private int age;

    public Student() {
    }

    public Student(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    // 咱们来手动定制equals()方法
    @Override
    public boolean equals(Object o) {
        // 两个对象堆内存地址相同,说明是同一个对象,自然内容也相同
        if(this == o){
            return true;
        }
        // 先判断是否是一个Student的实例对象,如果是向下转型进行比较,反之直接返回false
        if(!(o instanceof Student)){
            return false;
        }
        // 向下转型,继续判断每个值是否相等
        Student student = (Student)o;
        return this.name.equals(student.name) && this.age == student.age;
    }

    // 我这里使用idea一键重写了,具体该怎么重写hashCode()方法、有什么规则,暂不讨论
    @Override
    public int hashCode() {
        int result = name != null ? name.hashCode() : 0;
        result = 31 * result + age;
        return result;
    }
}

 

运行结果:

(如果没有重写hashCode()方法,下面两个int值是不同的,因为Object类默认实现的hashCode()方法是根据对象所存储的的堆内存地址计算出来的,既然是两个对象堆内存地址自然不同,因此hashCode不同!)

true
34671292
34671292

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值