Java基础系列-equals方法和hashCode方法
原创文章,转载请标注出处:《Java基础系列-equals方法和hashCode方法》
概述
equals方法和hashCode方法都是有Object类定义的。
public class Object {
public native int hashCode();
public boolean equals(Object obj) {
return (this == obj);
}
}
任何的类都是Object类的子类,所有它们默认都拥有这两个方法。
equals方法用于定义两个对象的比较方式,而hashCode方法是native方法,主要用户计算对象的hash值。
equals
equals方法主要用于定义两个对象的比较方式,默认的比较方式是比较内存地址,相对于基本类型来说就是值,而相对于引用类型来说就是堆中具体对象的地址。那么就只有值相同的基本类型,和同一个对象的两个引用才能相等。但是在我们实际业务系统中,两个对象的相等一般指的是两个对象的内容相同(逻辑相同),而不是说它两个是同一个对象,这种情况使用默认的equals就无法实现相等(因为两个不同对象地址值一定不同),这时候我们就需要对equals方法进行重写,定义新的比较方式。
准则
- 自省性:对于非null的x,存在:x.equals(x)返回true
- 对称性:对于非null的x和y,存在:x.equals(y)==y.equals(x)
- 传递性:对于非null的x、y、z,存在:当x.equals(y)返回true,y.equals(z)返回true,则x.equals(z)一定为true
- 一致性:对于非null的x和y,多次调用x.equals(y)所得的结果是不变的
- 非空性:对于非null的x,存在x.equals(null)返回false
重写
其实Java中已经为我们展示了如何重equals方法了,最经典的就是String的equals方法:
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
public boolean equals(Object anObject) {
// 首先判断两个对象是不是同一个,地址相同否
if (this == anObject) {
return true;
}
// 判断给定的对象是否是String类型,这里instanceof关键字是重写equals方法时经常使用的一个关键字
// instanseof用于判断右边的类型是否是当前对象的类型或者超类型,超接口类型等
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
// 校验两个字符串的长度相同否
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
// 循环校验两个字符串中的每个字符是否相同
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
}
注意,使用instanceof在针对存在子类的情况下,可能会出现违反对称性和传递性的情况,为了避免这种情况,可以通给getClass的方式比较类型。
自定义重写:
public class EqualsTest {
private int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Override
public boolean equals(Object obj) {
// 满足非空性
if(obj == null){
return false;
}
// 满足自省性
if(this == obj){
return true;
}
// 满足对称性、传递性、一致性
if(this.getClass() == obj.getClass()
&& this.getClass().getClassLoader() == obj.getClass().getClassLoader()
&& this.id == ((EqualsTest)obj).getId()){
return true;
}
return false;
}
}
注意:这里如果是有不同的类加载器加载的同一类的实例也是无法相等的。
hashCode
hashCode一般用于计算对象的hash值,它在类重写equals的时候一起重写,重写它的目的是为了保证equals相同的两个对象的hashCode结果一致,为什么要保证这一点呢,那就归结到java中的那几个基于Hash实现的集合上了,比如HashMap、HashSet等,这些集合需要用到对象的hash值来参与计算定位。
使用hashCode的目的就是为了散列元素,最终元素能否散列均匀和hashCode的实现息息相关,即为hash函数。
实现方式
- 链地址法(理解):在出现hash冲突的时候,在这个位置再插入新元素,并与原有元素形成一个链表,类似于HashMap的实现方式
- 开放寻址法(了解):在出现hash冲突的时候,在当前位置的附近寻找空位来存放新元素,这种方式只需要一种数据结构,不需要引入新的数据结构。其实就是为每个hash结果准备一个探查序列,用来存放发生hash冲突的元素。
- 线性探查法:当出现hash冲突,则在当前位置逐个向后寻找空位,将新元素保存到找到的第一个空位,当找到最后时,需要折返到一开头继续查找。由于探查序列固定,所以会引发一次集群问题。
- 二次探查法:出现冲突,不再逐个顺序探查,而是由某种函数计算的结果序列来探查,这个函数依赖于开始下标的平方,所以叫二次探查,开始下标的不同,序列就不相同,不同序列中会有重复的下标,由于每个下标开始的探查序列是固定的,所以会引发小规模集群,即二次集群问题。
- 双重散列法:要解决群集,就要想办法让相同hash结果的序列不同,最好让序列函数依赖于元素本身,保证当元素不同时,即使hash结果一致,但一旦发生冲突,不同的元素的序列是不同的(因为序列还要依赖元素本身,元素不同,序列结果就会不同),这样存在两个依赖变量的探查方法,可以极大的避免集群问题。
- 再HASH法(知道)
- 建立公共溢出区法(知道)
hashCode的实现方式并不是随手而来的,需要考虑各种情况,选择合适的方式来实现,举个例子,在Java的HashMap集合中,采用的就是链地址法来处理hash冲突。
参考:
- Java hashCode() 和 equals()的若干问题解答
- 白话算法(6) 散列表(Hash Table)从理论到实用(上)
- 白话算法(6) 散列表(Hash Table)从理论到实用(中)
- 白话算法(6) 散列表(Hash Table)从理论到实用(下)
Java基础系列-equals方法和hashCode方法的更多相关文章
- Java 如何重写对象的 equals 方法和 hashCode 方法
前言:Java 对象如果要比较是否相等,则需要重写 equals 方法,同时重写 hashCode 方法,而且 hashCode 方法里面使用质数 31.接下来看看各种为什么. 一.需求: 对比两个对 ...
- 详解equals()方法和hashCode()方法
前言 Java的基类Object提供了一些方法,其中equals()方法用于判断两个对象是否相等,hashCode()方法用于计算对象的哈希码.equals()和hashCode()都不是final方 ...
- 关于Object类的equals方法和hashCode方法
关于Object类的equals的特点,对于非空引用: 1.自反性:x.equals(x) return true : 2.对称性:x.equals(y)为true,那么y.equals(x)也为tr ...
- HashSet中存方用户自己定义数据类型数据,重写equals方法和hashCode方法
import java.util.Set; import java.util.HashSet; public class SetTest { public static void main(Strin ...
- 详解 equals() 方法和 hashCode() 方法
创建实体类时,最好重写超类(Object)的hashCode()和equals()方法 equals()方法: 通过该实现可以看出,Object类的实现采用了区分度最高的算法,即只要两个对象不是同一个 ...
- equals()方法和hashCode()方法详解
equals()方法和hashCode()方法详解 1. Object类中equals()方法源代码如下所示: /** * Object类中的equals()方法 */ public boolean ...
- java中equals方法和hashcode方法的区别和联系,以及为什么要重写这两个方法,不重写会怎样
一.在Object类中的定义为:public native int hashCode();是一个本地方法,返回的对象的地址值.但是,同样的思路,在String等封装类中对此方法进行了重写.方法调用得到 ...
- Java equals()方法和hashCode()方法
equals()方法 如果满足了以下任何一个条件,就不需要覆盖equals()方法: 1 类的每个实例本质上都是唯一的. 2 不关心类是否提供了“逻辑相等”的测试功能. 3 父类已经覆盖了equals ...
- JAVA正确地自定义比较对象---如何重写equals方法和hashCode方法
在实际应用中经常会比较两个对象是否相等,比如下面的Address类,它有两个属性:String province 和 String city. public class Address { priva ...
随机推荐
- 安卓开发笔记(二十八):仿写IOS switch选择器控件实现,checkbox
我们先来看看效果: 这里我们主要使用了github上的一个开源项目,配置起来比较方便,下面解释一下该如何使用:首先是:Gradle文件当中进行配置: dependencies { implementa ...
- 从壹开始 [ Nuxt.js ] 之一 || 为开源收录Bug之 TiBug项目 开篇讲
缘起 哈喽大家周二好呀,刚刚经历过了几天火车抢票,整个人都不好了,不知道小伙伴对今年的春节是否还一如既往的期待呢,眼看都要春节了,本来也想写篇2018总结篇,但是怕不免会出现鸡汤文的窠臼嫌疑,想想还是 ...
- python接口自动化(十七)--Json 数据处理---一次爬坑记(详解)
简介 有些 post 的请求参数是 json 格式的,这个前面发送post 请求里面提到过,需要导入 json模块处理.现在企业公司一般常见的接口因为json数据容易处理,所以绝大多数返回数据也是 j ...
- OpenResty 在又拍云容器平台中的应用
大家好,我是又拍云叶靖,今天主要分享 OpenResty 在又拍云容器平台中的应用.目前又拍云有很多产品,其中很多都使用了 OpenResty 技术,比如又拍云的 CDN .网关都是基于 OpenRe ...
- flutter初体验
flutter初体验 和flutter斗争了两个周末,基本弄清楚了这个玩意的布局和一些常用组件了. 在flutter里面,所有东西都是组件Widget.我们像拼接积木一样拼接Widget,拼接的关键词 ...
- ASP.NET Core中实现单体程序的事件发布/订阅
标题:ASP.NET Core中实现单体程序的事件发布/订阅 作者:Lamond Lu 地址:https://www.cnblogs.com/lwqlun/p/10468058.html 项目源代码: ...
- asp.net core系列 50 Identity 授权(中)
1.5 基于策略的授权 在上篇中,已经讲到了授权访问(authorization)的四种方式.其中Razor Pages授权约定和简单授权二种方式更像是身份认证(authentication) ,因为 ...
- windows&lunix下node.js实现模板化生成word文件
最近在做了一个小程序!里面有个功能就是根据用户提交的数据,自动生成一份word文档返回给用户.我也是第一次做这功能,大概思路就是先自己弄一份word模板,后台接受小程序发过来的数据,再根据这些数据将相 ...
- 『动态』动态JSON万能转换函数 + .Net40 dynamic动态数据绑定
不废话,调用代码: static void Main(string[] args) { string json = File.ReadAllText("2.txt", Encodi ...
- [PHP] 使用反射实现的控制反转
搬家进程中反射实现控制反转,样做的好处是可以通过配置项动态的控制下面那个类的属性 1.$this->getObject($class, $config->getConfig('param' ...