关于equals()和hashcode()的一些约定
本文章主要讨论和回答一下几个问题:
equals()的四大特性
equals()和hashcode()之间的关系,为什么我们经常说这两个方法要么都重写,要么都不重写?
HashMap、HashSet等容器为什么要求一定要重写equals()以及hashcode()
equals()
equals和hashcode方法我们都很了解,是Object类中的定义的方法,这意味着所有的类都隐式实现了这两个方法。
Object类中的equals方法的默认实现是比较对象标识(根据对象头信息),但是这个对我们没有任何意义。因此一般情况下我们要重写equals方法
equals方法一般有以下四个约定:
- 自反:对象必须等于自身
- 对称:x.equals(y) 必须返回与 y.equals(x) 相同的结果
- 传递性:如果 x.equals(y) 和 y.equals(z) 那么 x.equals(z)
- 一致:仅当包含在 equals() 中的属性发生更改时,equals() 的值才应更改
使用IDEA智能重写equals方法如下,比较两个对象相关属性的值是否全部一致。:
public class Student {
private String name;
private int age;
}
@Override
public 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);
}
hashcode()
hashcode方法也同样定义在Object类中,返回一个整数,表示该类的实例状态,要根据类的相等性定义来计算这个值,也就是说hashcode方法调用了equals方法,因此重写hashcode必须先重写equals,这样类的hashcode值才有意义。
hashcode同样有取得共识的约定:
- 内部一致性:只有当 equals() 中的属性发生变化时,hashCode() 的值才会发生变化
- 相等一致性:彼此相等的对象必须返回相同的 hashCode
- hash碰撞:不相等的对象可能具有相同的哈希码
从第二个约定我们可以推出,重写equals方法也必须同时重写hashcode方法,不然就违反了第二个规定
看到这里,我想我们已经解决了前面提出的第二个问题,equals和hashcode必须都被重写或者都不重写
但是,这只是一个约定,并非强制要求,如果不遵循这个约定会有什么问题呢?我们通过hashmap来举例
hashmap的key如何实现唯一性
我们知道map为了保证map的key是唯一的,我们需要重写key类的hashcode方法和equals方法。为什么呢?因为key的添加过程是这样的:
- 先查看key的hashcode是否已经存在
- 如果不存在,说明当前容器没有此key,直接添加
- 如果存在,有可能是相同的key,也有可能是产生了hash碰撞。使用equals进行进一步比较
因此使用hashmap必须重写这两个方法
如果不重写的话,可能会有重复的key被放入map中。举个例子:
HashMap<Student, Integer> studentIntegerHashMap = new HashMap<Student, Integer>();
Student tom1 = new Student("tom", 11);
Student tom2 = new Student("tom", 11);
studentIntegerHashMap.put(tom1,1);
studentIntegerHashMap.put(tom2,1);
正常情况下tom2是不会被添加到map集合中的,但是如果你不重写hashcode方法,使用的就是本地的hashcode方法,这两个对象的hashcode一定不同,因此都能被添加进集合中,这显然是我们不想看到的。
至于HashSet,有的朋友应该知道,HashSet的底层是通过HashMap实现的,因此也同样要实现这两个方法才能“去重”
总结
在本篇文章中,我们讨论了 equals() 和 hashCode() 的约定和使用。我们应该记住以下几点:
- 如果我们覆盖 equals(),则始终覆盖 hashCode(),反过来也一样
- 考虑使用 IDE 或第三方库来生成 equals() 和 hashCode() 方法
参考
关于equals()和hashcode()的一些约定的更多相关文章
- equals()与hashCode()方法协作约定
翻译人员: 铁锚 翻译时间: 2013年11月15日 原文链接: Java equals() and hashCode() Contract 图1 Java所有对象的超类 java.lang.Obje ...
- 一次性搞清楚equals和hashCode
前言 在程序设计中,有很多的“公约”,遵守约定去实现你的代码,会让你避开很多坑,这些公约是前人总结出来的设计规范. Object类是Java中的万类之祖,其中,equals和hashCode是2个非常 ...
- equals()和hashCode()区别?
equals()和hashCode()区别? ------------------------------------------------- equals():反映的是对象或变量具体的值,即两个对 ...
- 探索equals()和hashCode()方法
探索equals()和hashCode()方法 在根类Object中,实现了equals()和hashCode()这两个方法,默认: equals()是对两个对象的地址值进行的比较(即比较引用是否相同 ...
- Effective Java 第三版——10. 重写equals方法时遵守通用约定
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- java的equals()与hashCode()以及包装类中的实现
1. hashcode 1.1 hashcode来源 1.2 hashcode的形式 1.3 hashcode目的 1.4 hashcode规则 1.5 hashcode作用体现 1.6 重写hash ...
- Java == ,equals 和 hashcode 的区别和联系(阿里面试)
今天阿里的人问我 equals 与hashcode的区别,我答不上来, 仔细查了一下,做了总结: (1) == 这是Java 比较内存地址,就是内存中的对象: java中的==是比较两个对象在JVM中 ...
- 为什么要同时重写equals和hashcode
原文地址https://blog.csdn.net/tiantiandjava/article/details/46988461 原文地址https://blog.csdn.net/lijiecao0 ...
- 第8条:覆盖equals时请遵守通用约定
第8条:覆盖equals时请遵守通用约定 引言:尽管Object是一个具体类,但是设计它主要是为了拓展.它所有的非final方法(equals.hashCode.toString.clone和fina ...
随机推荐
- 团队任务拆解$\alpha$
项目 内容 班级:2020春季计算机学院软件工程(罗杰 任健) 博客园班级博客 作业要求 团队任务拆解 我们在这个课程中的目标 提升团队管理及合作能力,开发一项满意的工程项目 这个作业对我们实现目标的 ...
- CRM系统如何改善企业业务流程
工作流管理是CRM客户管理系统的一个重要功能.当企业进行业务管理和处理时,会有一套自己的工作流程.使用CRM系统,可以帮助企业改进整个工作流程,利用系统的流程设置模块,将各个部门所处理的活动定义为过程 ...
- MySQL之数据定义语言(DDL)
写在前面 本文中 [ 内容 ] 代表啊可选项,即可写可不写. SQL语言的基本功能介绍 SQL是一种结构化查询语言,主要有如下几个功能: 数据定义语言(DDL):全称Data Definition L ...
- jQuery 实现 全选/全不选/反选
<button id="getall" class="btn btn-warning">全选</button><button id ...
- linux中级之防火墙的数据传输过程
网络数据传输过程 netfilter在数据包必须经过且可以读取规则的位置,共设有5个控制关卡.这5个关卡处的检查规则分别放在5个规则链中(有的叫钩子函数(hook functions).也就是说5条链 ...
- Python3.x 基础练习题100例(91-100)
练习91: 题目: 时间函数举例1. 程序: if __name__ == '__main__': import time print (time.ctime(time.time())) print ...
- 归一化方法总结 | 又名“BN和它的后浪们“
前言: 归一化相关技术已经经过了几年的发展,目前针对不同的应用场合有相应的方法,在本文将这些方法做了一个总结,介绍了它们的思路,方法,应用场景.主要涉及到:LRN,BN,LN, IN, GN, FRN ...
- python rpc 的实现
所谓RPC,是远程过程调用(Remote Procedure Call)的简写,网上解释很多,简单来说,就是在当前进程调用其他进程的函数时,体验就像是调用本地写的函数一般.本文实现的是在本地调用远端的 ...
- leetcode中Java关于Json处理的依赖
leetcode的java代码提供的main函数中,往往有关于json的依赖...我找了许久才找到他们用的是这个json实现 <dependency> <groupId>com ...
- CAS(Compare and Swap)无锁算法-学习笔记
非阻塞同步算法与CAS(Compare and Swap)无锁算法 这篇问题对java的CAS讲的非常透彻! 锁的代价 1. 内核态的锁的时候需要操作系统进行一次上下文切换,加锁.释放锁会导致比较多的 ...