Java基础之浅谈hashCode()和equals()

 更新时间:2021年06月20日 17:18:54   作者:java技术爱好者_R  
今天给大家带来的是关于Java基础的相关知识,文章围绕着hashCode()和equals()展开,文中有非常详细的介绍及代码示例,需要的朋友可以参考下

写在前面

其实很早我就注意到阿里巴巴Java开发规范有一句话:只要重写 equals,就必须重写 hashCode

我想很多人都会问为什么,所谓知其然知其所以然,对待知识不单止知道结论还得知道原因。

hashCode方法

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

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

equals方法

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

Object类的equals方法是用“”号进行比较,在很多时候,因为号比较的是两个对象的内存地址而不是实际的值,所以不是很符合业务要求。所以很多时候我们需要重写equals方法,去比较对象中每一个成员变量的值是否相等。

问题来了

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

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

下面我们做一个试验,有一个User类,只重写equals()方法,然后放到Set集合中去重。

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方法
}

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

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

按道理我们预期会去重,只剩下一个“张三”的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会认为都不相等。

这是重写hashCode方法的情况,因为是用对象所有的成员变量的值计算出的哈希码,所以只要两个对象的成员变量都是相等的,则生成的哈希码是相同的。

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

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

总而言之:

  • 哈希码不相等,则两个对象一定不相同。
  • 哈希码相等,两个对象不一定相同。
  • 两个对象相同,则哈希码和值都一定相等。

总结

所以回到开头讲的那句,只要重写 equals,就必须重写 hashCode,这是一个很重要的细节,如果不注意的话,很容易发生业务上的错误。

特别是有时候我们明明用了HashSet,distinct()去重,但是就是不生效,这时应该回头看看重写了equals()和hashCode()方法了吗?

到此这篇关于Java基础之浅谈hashCode()和equals()的文章就介绍到这了,更多相关hashCode()和equals()内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java ResultSet案例讲解

    Java ResultSet案例讲解

    这篇文章主要介绍了Java ResultSet案例讲解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-08-08
  • spring声明式事务@Transactional底层工作原理

    spring声明式事务@Transactional底层工作原理

    这篇文章主要为大家介绍分析spring声明式事务@Transactional底层工作原理,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步早日升职加薪
    2022-02-02
  • SpringMVC @RequestMapping注解详解

    SpringMVC @RequestMapping注解详解

    本文主要介绍了SpringMVC @RequestMapping注解详解,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-12-12
  • SpringBoot整合Mybatis实现高德地图定位并将数据存入数据库的步骤详解

    SpringBoot整合Mybatis实现高德地图定位并将数据存入数据库的步骤详解

    这篇文章主要介绍了SpringBoot整合Mybatis实现高德地图定位并将数据存入数据库的步骤详解,本文分步骤通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-01-01
  • java批量修改文件名的实现方法

    java批量修改文件名的实现方法

    这篇文章主要介绍了 java批量修改文件名的实现方法的相关资料,实现批量修改文件下的所有文件的文件名,具有一定的参考价值,需要的朋友可以参考下
    2017-07-07
  • java使用电脑摄像头识别二维码

    java使用电脑摄像头识别二维码

    这篇文章主要为大家详细介绍了java使用电脑摄像头识别二维码,从摄像头获取图像,再根据图片解析出二维码信息,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-10-10
  • JavaGUI模仿QQ聊天功能完整版

    JavaGUI模仿QQ聊天功能完整版

    这篇文章主要为大家详细介绍了JavaGUI模仿QQ聊天功能完整版,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-07-07
  • 微信小程序登录状态java后台解密

    微信小程序登录状态java后台解密

    这篇文章主要为大家详细介绍了微信小程序登录状态java后台解密,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-12-12
  • 带你一文深入认识Java String类

    带你一文深入认识Java String类

    这篇文章主要介绍了带你一文深入认识Java String类,String 类在Java中是很常用的类,很重要的类,在后续的学习中经常会用到,是后续学习的基础, 文章围绕主题展开更多详细内容,需要的小伙伴可以参考一下,希望对你的学习有所帮助
    2022-06-06
  • java 使用DecimalFormat进行数字的格式化实例详解

    java 使用DecimalFormat进行数字的格式化实例详解

    这篇文章主要介绍了java 使用DecimalFormat进行数字的格式化实例详解的相关资料,需要的朋友可以参考下
    2017-06-06

最新评论