HashCode()和equals()的区别

HashCode简介

hashCode()方法的作用是获取哈希码,返回的是一个int整数

Object类中的hashCode()方法定义如下

public native int hashCode();

哈希码的作用是确定对象在哈希表的索引下标。比如HashSet和HashMap就是使用了hashCode方法确定索引下标。如果两个对象返回的hashCode相同,就被称为“哈希冲突”。

equals简介

equals()方法的作用很简单,就是判断两个对象是否相等,equals()方法是定义在Object类中,而所有的类的父类都是Object,所以如果不重写equals方法则会调用Object类的equals方法。

Object类中的equals()方法定义如下

public boolean equals(Object obj) {    
	return (this == obj);
}

在equals()方法中的==,那么在Java中有什么含义呢,

我们都知道在Java中分为基本数据类型和引用数据类型。那么==在这两个类型中作用是不一样的。

  • 基本数据类型:比较的是==两边值是否相等
  • 引用数据类型:比较的是==两边内存地址是否相等

基本数据类型包括:byte,short,char,int,long,float,double,boolean

而通过Java文档中的equals()方法描述,所有要实现自己的equals()方法都要遵守下面几个规则

  • 自反性:对于任何对象x,x.equals(x)应该返回true。
  • 对称性:对于任何两个对象x和y,如果x.equals(y)返回true,那么y.equals(x)也应该返回true。
  • 传递性:对于多个对象x,y,z,如果x.equals(y)返回true,y.equals(z)返回true,那么y.equals(z)也应该返回true。
  • 一致性:对于两个非空对象x,y,在没有修改此对象的前提下,多次调用返回的结果应该相同。
  • 对于任何非空的对象x,x.equals(null)都应该返回false。

1、类中重写HashCode和equals方法比较两个对象是否相等

  • 两个对象通过equals比较是相等的,那么HashCode肯定相等。

  • 两个对象通过HashCode比较是相等的,那么equals不一定相等。

  • 因此,equals 方法被覆盖过,则 hashCode 方法也必须被覆盖

面试题:
重写equals()方法就可以比较两个对象是否相等,为什么还要重写hashcode()方法呢?

因为HashSet、HashMap底层在添加元素时,会先判断对象的hashCode是否相等,如果hashCode相等才会用equals()方法比较是否相等。换句话说,HashSet和HashMap在判断两个元素是否相等时,会先判断hashCode,如果两个对象的hashCode不同则必定不相等。

以下是源码展示:在这里插入图片描述

2、HashSet保证元素的唯一性

代码演示:
有一个User类,只重写equals()方法,然后放到HashSet集合中去重

public class User {

    private String id;

    private String name;

    private Integer age;
    
    public User(String id, String name, Integer age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }
    
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        return Objects.equals(id, user.id) &&
            Objects.equals(name, user.name) &&
            Objects.equals(age, user.age);
    }
    
    //此处省略getter、setter、toString方法
}

然后我们循环创建3个成员变量的值都是一样的User对象,最后放到Set集合中去重

public static void main(String[] args) {
    List<User> list = new ArrayList<>();
    for (int i = 0; i < 3; i++) {
        User user = new User("1", "张三", 18);
        list.add(user);
    }
    Set<User> set = new HashSet<>(list);
    for (User user : set) {
        System.out.println(user);
    }
}

按道理我们预期会去重,只剩下一个“张三”的user,但实际上因为没有重写hashCode方法,所以没有去重。

运行结果
在这里插入图片描述
接着我们在User类里面重写一些hashCode方法再试试,其他不变

public class User {
    //其他不变
    
    //重写hashCode方法
    @Override
    public int hashCode() {
        return Objects.hash(id, name, age);
    }
}

运行结果

在这里插入图片描述

究其原因在于HashSet会先判断hashCode是否相等,如果hashCode不相等就直接认为两个对象不相等,不会再用equals()比较了。我们不妨看看重写hashCode方法和不重写hashCode方法的哈希码。

这是不重写hashCode方法的情况,每个user对象的哈希码都不一样,所以HashSet会认为都不相等。

在这里插入图片描述
在这里插入图片描述
那么有些人看到这里,就会问,如果两个对象返回的哈希码都是一样的话,是不是就一定相等?

答案是不一定的,因为HashSet、HashMap判断哈希码相等后还会再用equals()方法判断。

总结:
1.HashCode方法和equals方法都是Object类中的方法,即所有对象都有equals方法和HashCode方法;
2.两个对象通过equals比较是相等的,那么HashCode肯定相等;相反的,两个对象通过HashCode比较是相等的,那么equals不一定相等;
3.只要重写equals方法,就必须重写HashCode方法;

完!

  • 14
    点赞
  • 91
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

华山之仔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值