equals与hashCode
当我们需要将自己的类存入HashMap或HashSet时一般都要重写其equals与hashCode方法,但在重写时要符合规范否则会出问题。
1、equals方法
首先equals方法需要满足如下几点性质:
- 自反性:对于非空引用x,x.equals(x)的的结果一定为真。
- 对称性:对于非空引用x,y,如果x.equals(y)为真,y.equals(x)一定为真。
- 传递性:对应非空引用x,y,z,如果x.equals(y)为真,y.equals(z)为真,x.euqals(z)一定为真。
- 幂等性:对于非空引用x,y,如果两个对象没有被改变,多次调用x.equals(y),其返回值不变。
这些性质中自反性与幂等性一般不会被破化,但对称性与传递性在一些情况下却无法满足。
1.1、对称性
public final class CaseInsensitiveString {
private final String s; @Override // 不满足对称性
public boolean equals(Object o) {
if (o instanceof CaseInsensitiveString)
return s.equalsIgnoreCase(((CaseInsensitiveString) o).s);
if (o instanceof String)
return s.equalsIgnoreCase((String) o);
return false;
}
}
上边的例子,CaseInsensitiveString在实现equals方法时对原始String类进行了支持。
CaseInsensitiveString cis = new CaseInsensitiveString("Polish");
String s = "polish";
考虑变量cis与s,cis.equals(s)结果为真,但是s.equals(cis)为假,不满足对称性。
List<CaseInsensitiveString> list = new ArrayList<>();
list.add(cis);
这时list.contains(s)的结果为假。
1.2、传递性
public class Point {
private final int x;
private final int y; @Override public boolean equals(Object o) {
if (!(o instanceof Point))
return false;
Point p = (Point)o;
return p.x == x && p.y == y;
}
}
以一个二维坐点类为例,如果我们需要对其进行扩展,添加一个颜色属性。
public class ColorPoint extends Point {
private final Color color;
public ColorPoint(int x, int y, Color color) {
super(x, y);
this.color = color;
}
}
ColorPoint该如何实现equals方法呢,先看第一种实现方式:
// 不满足对称性
@Override public boolean equals(Object o) {
if (!(o instanceof ColorPoint))
return false;
return super.equals(o) && ((ColorPoint) o).color == color;
}
这时Point与ColorPoint比较(point.equals(colorPoint))结果可以为真,但是ColorPoint与Point比较时结果永远为假,即不满足对称性。第二种实现方式:
// 不满足传递性
@Override public boolean equals(Object o) {
if (!(o instanceof Point))
return false;
if (!(o instanceof ColorPoint))
return o.equals(this);
return super.equals(o) && ((ColorPoint) o).color == color;
}
这种方式在比较时区别对待Point跟ColorPoint,但假如有三个对象(1, 2 ,红),(1,2),(1,2,绿),(1,2,红)等于(1,2),(1,2)等于(1,2,绿),但是(1,2,红)却不等于(1,2,绿),即不满足传递性。
1.3、模板
实现equals方法一般可以遵循一个模板,首先用==操作符检查被比较对象是否是自己本身,然后用instanceof操作符检查类型,再将其转换为正确的类型,最后逐个对有意义的字段进行比较。
public final class PhoneNumber {
private final int areaCode, prefix, lineNum; @Override public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof PhoneNumber))
return false;
PhoneNumber pn = (PhoneNumber)o;
return pn.lineNum == lineNum && pn.prefix == prefix
&& pn.areaCode == areaCode;
}
}
2、hashCode方法
重写equals方法后一定要记得重写hashCode方法,因为hashCode也要满足几条性质:
- 当一个对象的属性没有被修改时,多次调用其hashCode函数返回值不变。
- 如果两个对象被equals函数判定为相等,那么这两个对象的hashCode函数的返回值也一定相等。
- 如果两个对象被equals函数判定为不等,那么这两个对象的hashCode函数的返回值可以是相等的。
这里说的对象的属性是指在equals函数中使用到的属性。上述性质中提到,如果两个对象被equals函数判定为相等,那这两个对象的hashCode函数的返回值必须是相等的,如果我们的类没有重写hashCode函数就无法满足这条性质,在使用HashMap函数时也会出问题。
Map<PhoneNumber, String> m = new HashMap<>();
m.put(new PhoneNumber(707, 867, 5309), "Jenny");
接着调用m.get(new PhoneNumber(707, 867,5309)),但它并不会返回"Jenny"而是null,因为PhoneNumber类没有重写hashCode函数,根据Object类的hashCode函数,新对象可能会被映射到另外的哈希桶中导致查找失败。
重写hashCode函数也有章可循:
- 声明一个int类型的变量result,其值初始化为第一个属性的哈希值。
- 对于每个剩余的属性,分别计算其哈希值c。
- 合并结果result = 31 * result + c。
分别计算对象属性哈希值时,根据属性的类别,方法如下:
- 原始类型:使用Type.hashCode(f),Type是原始类型的装箱类型。
- 引用类型:调用该对象的hashCode函数,如果对象为null则使用默认值,一般为0。
- 数组类型:使用Arrays.hashCode函数,如果数组为null则使用默认值,一般为0。
对于上文中的PhoneNumber类,它的hashCode函数实现如下:
@Override public int hashCode() {
int result = Short.hashCode(areaCode);
result = 31 * result + Short.hashCode(prefix);
result = 31 * result + Short.hashCode(lineNum);
return result;
}
equals与hashCode的更多相关文章
- How to implement equals() and hashCode() methods in Java[reproduced]
Part I:equals() (javadoc) must define an equivalence relation (it must be reflexive, symmetric, and ...
- JAVA中用堆和栈的概念来理解equals() "=="和hashcode()
在学习java基本数据类型和复杂数据类型的时候,特别是equals()"=="和hashcode()部分时,不是很懂,也停留了很长时间,最后终于有点眉目了. 要理解equals() ...
- 关于equals、hashcode和集合类的小结
一.首先明确一点:equals()方法和hashcode()方法是Object类里的方法. 查看源码可以知道,在Object类中equals(obj)方法直接返回的是 this == obj 的值. ...
- Object方法equals、hashCode
java知识背景: 1)hashCode()方法返回的是Jvm的32位地址 2)==比较的是对象在jvm中的地址 3)Object的equals()比较的就是jvm物理地址 4)比较2个对象使用equ ...
- Java中的equals和hashCode方法
本文转载自:Java中的equals和hashCode方法详解 Java中的equals方法和hashCode方法是Object中的,所以每个对象都是有这两个方法的,有时候我们需要实现特定需求,可能要 ...
- Java提高篇——equals()与hashCode()方法详解
java.lang.Object类中有两个非常重要的方法: 1 2 public boolean equals(Object obj) public int hashCode() Object类是类继 ...
- Java中==、equals、hashcode的区别与重写equals以及hashcode方法实例(转)
Java中==.equals.hashcode的区别与重写equals以及hashcode方法实例 原文地址:http://www.cnblogs.com/luankun0214/p/4421770 ...
- java中equals和hashCode方法的解析
解析Java对象的equals()和hashCode()的使用 前言 在Java语言中,equals()和hashCode()两个函数的使用是紧密配合的,你要是自己设计其中一个,就要设计另外一个.在多 ...
- Java实战equals()与hashCode()
一.equals()方法详解 equals()方法在object类中定义如下: 代码 public boolean equals(Object obj) { return (this == obj); ...
- 一次性搞清楚equals和hashCode
前言 在程序设计中,有很多的“公约”,遵守约定去实现你的代码,会让你避开很多坑,这些公约是前人总结出来的设计规范. Object类是Java中的万类之祖,其中,equals和hashCode是2个非常 ...
随机推荐
- protobufjs@6.8.8 postinstall: `node scripts/postinstall`
由于Node.js 版本太低了, 使用最新版用 Node.js =================================== 以下解决方法来源于网络 npm ERR! Windows_NT ...
- k8s记录-docker导入导出改标签
docker save <repository>:<tag> -o <repository>.tar docker save mysql:latest -o m ...
- matlab学习笔记11_3高维数组操作 filp, shiftdim, size, permute, ipermute
一起来学matlab-matlab学习笔记11 11_3 高维数组处理和运算 filp, shiftdim, size, permute, ipermute 觉得有用的话,欢迎一起讨论相互学习~Fol ...
- hive的分桶原理
套话之分桶的定义: 分桶表是对列值取哈希值的方式,将不同数据放到不同文件中存储.对于 hive 中每一个表.分区都可以进一步进行分桶. 列的哈希值除以桶的个数来决定每条数据划分在哪个桶中.(网上其它定 ...
- [转]Ubuntu18.04 主题美化以及常用软件
原文地址:https://www.jianshu.com/p/7d153a484f72
- EF Code First 快速创建
以.net framework为例,包括数据库管理类库和启动项目两个项目文件 数据库管理类库 新建一个类库,名称为XXX.Database 管理nuget包,引入库EntityFramework 6. ...
- 【maven学习】pom.xml文件详解
环境 apache-maven-3.6.1 jdk 1.8 eclipse 4.7 POM是项目对象模型(Project Object Model)的简称,它是Maven项目中的文件,使用XML表示, ...
- Elasticsearch在windows上安装与使用
Elasticsearch简称ES. 是一个全文搜索服务器,也可作为NoSQL数据库,存储任意格式的文档和数据,也可做大数据的分析,是一个跨界开源产品. ES的特点: 全文搜索引擎 文档存储和查询 大 ...
- PHP urlencode空格被转为+的问题
我想既然各位点进来,绝大数是因为你遇到了空格被转为+号所带来的坑 不过没关系,解决方案很简单:使用rawurlencode()来进行编码即可~此函数遵循RFC 3986标准,空格会被转为%20 同时, ...
- Redis Sentinel分布式集群
helm部署Redis哨兵分布式集群 Redis Sentinel集群 介绍 Redis Sentinel集群是由若干Sentinel节点组成的分布式集群,可以实现故障发现.故障自动转移.配置中心和客 ...