本文章主要讨论和回答一下几个问题:

  • 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()的一些约定的更多相关文章

  1. equals()与hashCode()方法协作约定

    翻译人员: 铁锚 翻译时间: 2013年11月15日 原文链接: Java equals() and hashCode() Contract 图1 Java所有对象的超类 java.lang.Obje ...

  2. 一次性搞清楚equals和hashCode

    前言 在程序设计中,有很多的“公约”,遵守约定去实现你的代码,会让你避开很多坑,这些公约是前人总结出来的设计规范. Object类是Java中的万类之祖,其中,equals和hashCode是2个非常 ...

  3. equals()和hashCode()区别?

    equals()和hashCode()区别? ------------------------------------------------- equals():反映的是对象或变量具体的值,即两个对 ...

  4. 探索equals()和hashCode()方法

    探索equals()和hashCode()方法 在根类Object中,实现了equals()和hashCode()这两个方法,默认: equals()是对两个对象的地址值进行的比较(即比较引用是否相同 ...

  5. Effective Java 第三版——10. 重写equals方法时遵守通用约定

    Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...

  6. java的equals()与hashCode()以及包装类中的实现

    1. hashcode 1.1 hashcode来源 1.2 hashcode的形式 1.3 hashcode目的 1.4 hashcode规则 1.5 hashcode作用体现 1.6 重写hash ...

  7. Java == ,equals 和 hashcode 的区别和联系(阿里面试)

    今天阿里的人问我 equals 与hashcode的区别,我答不上来, 仔细查了一下,做了总结: (1) == 这是Java 比较内存地址,就是内存中的对象: java中的==是比较两个对象在JVM中 ...

  8. 为什么要同时重写equals和hashcode

    原文地址https://blog.csdn.net/tiantiandjava/article/details/46988461 原文地址https://blog.csdn.net/lijiecao0 ...

  9. 第8条:覆盖equals时请遵守通用约定

    第8条:覆盖equals时请遵守通用约定 引言:尽管Object是一个具体类,但是设计它主要是为了拓展.它所有的非final方法(equals.hashCode.toString.clone和fina ...

随机推荐

  1. 1Spring注入小结

    Spring注入小结 (在Application.xml中) Spring学习笔记 周芋杉2021/5/14 1.基本注入类型注入 注入前的准备 <bean id="#配置文件的唯一标 ...

  2. 前端Node的实用方法

    Node 一.什么是Node Node是以基于Chrome V8引擎的JavaScript运行环境,使用了一个事件驱动.非阻塞式I/O模型(I/O是 input/output的缩写,即输入输出端口,在 ...

  3. 源码安装Python3

    源码安装Python3 一.安装Python3需要的依赖包 [root@localhost ~]# yum install -y gcc make wget openssl openssl-devel ...

  4. shell基础之多功能nginx(安装、重启、停止等)

    1 #!/bin/bash 2 #要求:检查本机是否已编译安装nginx,检查本机是否存在nginx源码包,编译安装nginx,实现开启.停止.查看状态等功能 3 #检查是否已编译安装nginx 4 ...

  5. 如何查看自己的电脑 CPU 是否支持硬件虚拟化

    引言 在你安装各种虚拟机之前,应该先测试一下自己的电脑 CPU 是否支持硬件虚拟化. 如果你的电脑比较老旧,可能不支持硬件虚拟化,那么将无法安装虚拟机软件. 如何查看自己 CPU 是否支持硬件虚拟化 ...

  6. Linux(CentOS 7) 安全加固之非业务端口服务关闭 postfix port 25

    目录 关闭TCP 25 端口对应的服务 1. 确认对应端口的进程 2. 查找与关闭对应服务 3. 确认结果,端口已关闭 关闭TCP 25 端口对应的服务 [0 root@Qvps /root] #ca ...

  7. Python Xpath语法

    Python    Xpath语法   一.选取节点 常用的路劲表达式: 表达式 描述 实例   nodename 选取nodename节点的所有子节点 xpath('//div') 选取了div节点 ...

  8. scrapy使用response.body时编码问题

    scrapy使用response.body时编码问题 摘要:scrapy使用response.body时编码问题.如果在使用responses.body获取数据时,需要将其编码转换成unicode,即 ...

  9. sql批量插入缓慢

    1.有一个普通的表t_asset,只有2个字段id,ip 没有索引 2.当用insert into t_asset(id,ip) values(?,?),(?,?) 1200多条记录时,发现竟然用了3 ...

  10. npm ERR! Error: tunneling socket could not be established的解决问题

    一般是代理问题 可以通过在命令行运行下列命令解决: npm run server npm run webdriver-update