为什么重写 equals 方法就必须重写 hashCode 方法?

news/2024/11/30 14:39:36/

简答版

        因为我们在使用 HashMap 或 HashSet 集合类的时候,需要用到哈希表,哈希表必须满足 两个对象 equals 返回 true时,两个对象 hashCode 返回的哈希值必须相同,而我们重写equals方法后,可能导致两个对象 equals 返回 true ,而 hashCode 返回的哈希值不相同,导致哈希表中存储了两个相同的对象

详答版

我们知道

  • 当两个对象 equals 返回 true 时,则两个对象就是相同的
  • 哈希表中不能存储两个相同的元素

而 哈希表 的原理是

  • 先比较两个对象的哈希值,如果哈希值不同,则这两个对象不可能相同,无需调用 equals 方法进行比较
  • 如果哈希值相同,这两个对象不一定相等,因此会再使用 equals 方法进行比较,来确定这两个对象是否相等
  • 并且哈希表中不能存储两个相同的元素 

因此 equals 方法 和 hashCode方法必须满足

  • hashCode相同时,equals 方法不一定返回 true
  • equals 方法返回 true 时,两个对象 hashCode 返回的哈希值必须相同

而如果重写了 equals 方法,而没有重写 hashCode 方法,就有可能导致 equals 返回true,而hashCode 返回的哈希值不相同

那么哈希表在存储数据的时候,比较到两个对象的哈希值不相同,就认为两个对象不同,不在调用equals方法,将两个对象都存储在哈希表中,这就导致了哈希表的错误

我们看下面的一个例子

import java.util.Objects;public class Student {String name;int age;public Student(String name, int age) {this.name = name;this.age = age;}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Student student = (Student) o;return age == student.age && Objects.equals(name, student.name);}}

上面的Student类我们重写了equals方法,但没有重写hashCode方法,然后进行测试

public class Test {public static void main(String[] args) {Student student01=new Student("张三",18);Student student02=new Student("张三",18);System.out.println(student01.equals(student02));Set<Student> studentSet = new HashSet<>();studentSet.add(student01);studentSet.add(student02);System.out.println(studentSet);}}

我们看到 HashSet 是 不可重复 的集合,却存入了两个相同的对象

现在我们重写hashCode方法

import java.util.Objects;public class Student {String name;int age;public Student(String name, int age) {this.name = name;this.age = age;}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Student student = (Student) o;return age == student.age && Objects.equals(name, student.name);}@Overridepublic int hashCode() {return Objects.hash(name, age);}
}

在进行相同的测试

我们看到了这次就存储进一个对象 

结论

重写equals方法的时候一定要重写hashCode方法

我们在自定义类的时候,equals方法默认使用 == 比较对象地址,而我们一般会重写以比较对象属性,而在idea中,当我们重写equals方法的时候,会自动帮我们重写hashCode方法


http://www.ppmy.cn/news/939661.html

相关文章

mysql数据库时区修改,国际时间变北京时间

select now(); show variables like ‘%time_zone%’; set global time_zone ‘8:00’; set time_zone ‘8:00’; select now();

用python修改时区为北京时间

昨天在项目封板前发现在aws的数据库存的时间不是北京时间&#xff0c;一开始以为是数据库的问题&#xff0c;后来发现是python导致的。查阅资料&#xff0c;发现需要使用pytz包的timezone模块。 之后 from datetime import datetime from pytz import timezone 因为在网上看到有…

Kali 2020修改系统为北京时间

1.运行tzselect设置时区&#xff0c;设置完后&#xff0c;按照提示将制定配置添加到.profile文件&#xff0c;文件夹视图Ctrlh查看隐藏文件。 2.修改完时区后重新登录&#xff0c;发现时间相差一小时&#xff0c;且格式为EST时间&#xff0c;而北京时间应以CST表示&#xff0c;…

Cesium 修改当前时间,显示北京时间

viewer.clock.currentTime Cesium.JulianDate.addHours(Cesium.JulianDate.now(new Date()), 8, new Cesium.JulianDate());

把格林威治时间转换为北京时间的函数

create or replace function Fun_SecondToTime(iamt number) return varcharasmytime varchar(24);begin select to_char(to_date(19700101,yyyymmdd)(iamt/60/60/24)(8/24),yyyy-mm-dd hh24:mi:ss) into mytime from dual; return mytime; end Fun_SecondToTime;

修改Centos时间为北京时间

在我们开发中&#xff0c;由于Centos默认时间并不是北京时间&#xff0c;那我们该如何修改为北京时间呢。 1.通过date命令查看当前服务器时间 date 2.删除本地时间并设置时区为上海 rm -rf /etc/localtime ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime 3.启动ntpd…

mysql修改为北京时间

1.查看mysql当前时区&#xff1a;show variables like ‘%time_zone%’ 发现是系统默认时间&#xff1a;system_time_zone&#xff1a;UTC&#xff0c;time_zone&#xff1a;system 2.docker的mysql的配置文件copy出来并修改后覆盖。 docker cp aiq_mysql:/etc/mysql/mysql.con…

centos离线修改时间为北京时间

查看时区 date需要修改的时区文件到底要用哪个&#xff1f;可以使用tzselect 命令查看 tzselect 首先列出七大洲的英文&#xff0c;如Asian 然后列出亚洲的国家和地区列表&#xff0c;选择中国china 然后可以看到china下的2个时区文件&#xff0c;一个是北京 一个是新疆 这里…