[Java] Object方法浅析(一): equals与hashCode

Java(二十九)Object类 hashcode equals方法 根据默认实现,它比较的是对象的引用是否相等,即比较两个对象是否是同一个实例。如果需要重写equals方法,应该重写hashcode方法.原生equals是比较对象是否相同,hashcode内存地址换算出来的一个值,如果只重写equals方法,而不重写hashCode方法的话,就回出现因为equals()两个对象相同,但是原先的hashCode()对应的值不同。Java.java.lang包下的核心类,Object类是所有类的父类,任何一个类如果没有明确的继承一个父类的话,那么它就是Object的子类; 阅读详情

摘要

  • equals描述的是一种等价关系,不仅仅是引用相等
  • equals重载需要满足自反性、对称性与传递性
  • 任何实例equals(null)需返回false,且多次调用equals返回值不变
  • hashCode返回对象的哈希值,多次调用hashCode返回值不变
  • hashCode不一定与内存地址相关
  • hashCode会发生碰撞
  • hashCode与equals密切相关
    • equals返回true的两个实例,hashCode值必须一样
    • hashCode值一样的两个实例,其equals方法返回不一定为true(可能有哈希碰撞等因素)

equals

equals是Object类的一个方法,常用来比较两个对象是否“相等”。当然,equals方法描述的相等是广义的,实际上应该是离散数学中的等价关系。

等价关系(equivalence relation)

等价关系概念

等价关系等同于集合的划分,简单来说就是物品分类,比如定义一个车辆集合Cars,定义分类规则(二元关系)为同种颜色的车,那么所有红色的车划分为一堆(等价类),所有绿色的车为另一堆。每辆车都存在且只存在于一堆中,所有堆的合起来等同于Cars。

等价关系 - 同种颜色车辆

划分的好处在于每个等价类中的个体都是等价的,均能代表整个类(如红色的普桑可以代表红色的车)。且等价类之间互斥,任何一个元素均只包含在一个等价类中。

equals重载

等价关系不同于相等,它在不同的类中可以有不同的规则,equals在不同类中也被不同重载。

在Object类中,只有同一个对象才被认定为等价。

Object.class  
public boolean equals(Object obj) {
    return (this == obj);
}

而在Integer类中,同为Integer类且值相等则便认为等价,而不仅仅同一个引用。

Integer.class
public boolean equals(Object obj) {
    if (obj instanceof Integer) {
        return value == ((Integer)obj).intValue();
    }
    return false;
}

但无论规则是什么,等价关系必须满足定义的三大原则:

1. 自反性:对于任何非空的x,x.equals(x)都应该返回true。
2. 对称性:对于任何非空x和y,当且仅当x.equals(y)返回true时,    y.equals(x)也应该返回true。
3. 传递性:对于任何非空x,y,z,如果x.equals(y)返回true,y.equals(z)返回true,那么x.equals(z)也应该返回true。

此外,对于Java来说,还需满足另外两个原则:

4. 一致性:如果x和y的引用没有发生变化,多次调用x.equals(y)的结果应该相同。
5. 关于null:对于任何非空的x,x.equals(null)都应该返回true。

例如自定义Person类,当身份证identity号相等时候便可以认为两个实例等价,可以这样写:

 static class Person {

    public String name;
    public long identity;

    public Person(String name, long identity) {
        this.name = name;
        this.identity = identity;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof Person) {
            if (((Person) obj).identity == this.identity) {
                return true;
            }
        }
        return false;
    }
}

  测试类 
  @Test
  public void testEqual() throws Exception {
        Person x = new Person("aa", 1234);
        Person y = new Person("aa", 12345);
        Person z = new Person("bb", 1234);
        Assert.assertTrue(x.equals(x));
        Assert.assertTrue(x.equals(z));
        Assert.assertTrue(z.equals(x));
        Assert.assertFalse(x.equals(y));
        Assert.assertFalse(x.equals(null));
    }

hashCode

hashCode方法返回的是对象的哈希值。

Object类的hashcode方法取决于JVM的实现,比较典型的一种实现是基于内存地址进行哈希运算,此外也有基于伪随机数的实现。

需要注意的是hashCode与equals一样,多次调用不改变返回值。所以每个对象一旦计算出其identity hash code之后,在该对象死之前都必须保持同一个identity hash code值不可以改变,而不是每次基于内存地址运算(JVM GC会影响内存地址)。

hashCode 与 equals联系

hashCode与equals方法密切相关:两个equals为true的实例必须返回相同的hashCode。这在HashMap等类的使用中是非常有用的。

套用之前的Person类,我们知道Set具有去重功能,但是如果不重写hashCode,纵然两个Person实例是等价的,也是不能达到去重的效果

public void testHash() throws Exception {
    HashSet<Person> set = new HashSet<>();
    Person a = new Person("123", 123);
    Person b = new Person("123", 123);
    set.add(a);
    set.add(b);
    System.out.print("set size : " + set.size());
}

 输出 
 set size : 2

下面重写hashCode方法使其与equals方法相关

@Override
public int hashCode() {
      return (int) identity;
}

重新run后输出
set size : 1

显然这样比较符合人的习惯,这种影响广泛存在于基于hashCode的容器类中,例如HashMap的contains方法等。

所以,一般来说重写了equals方法就需要重写hashCode方法。比如Object中equals判断的是否为相同的引用,因此hashCode基于引用内存地址返回。在Integer中判断的是Integer的value值,因此hashCode值则直接返回的是value值。

哈希碰撞

但需要注意的是,hashCode相同的两个实例,equals方法不一定会返回true。因为hashCode是一种空间映射函数,空间大的数据映射至小空间则势必会产生哈希碰撞。

空间映射

举个简单的例子

String.class
public int hashCode() {
    int h = hash;
    if (h == 0 && count > 0) {
        for (int i = 0; i < count; i++) {
            h = 31 * h + charAt(i);
        }
        hash = h;
    }
    return h;
}

上述代码为String源码,String的hashCode方法上转换成函数等同于:

hashCode = s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]  

简单来说就是讲其字符转换成31进制。

我们这样构造两个String实例

public void testHash() throws Exception {
    char A = 1;
    char B = 2;
    char C = 33;

    String aString = String.valueOf(A) + String.valueOf(B);
    String bString = String.valueOf(C);

    System.out.println("aString length: " + aString.length());
    System.out.println("bString length: " + bString.length());
    System.out.println("aString equals bString: " + aString.equals(bString));
    System.out.println("aString hashCode: " + aString.hashCode());
    System.out.println("String hashCode: " + bString.hashCode());
}

输出为:

aString length: 2
bString length: 1
aString equals bString: false
aString hashCode: 33
String hashCode: 33

显然,两个完全不一样的String对象产生可哈希碰撞。

关于数字31的引申

String equals方法中选31也是为了减少哈希碰撞,引用Effective Java中的原话来说

《Effective Java》

之所以选择31,是因为它是个奇素数。
如果乘数是偶数,并且乘法溢出的话,信息就会丢失,因为与2相乘等价于移位运算。
使用素数的好处并不是很明显,但是习惯上都使用素数来计算散列结果。
31有个很好的特性,就是用移位和减法来代替乘法,可以得到更好的性能:31*i==(i<<5)-i。现在的VM可以自动完成这种优化。

关于奇数,在计算机中,一个数乘偶数表现为该数字左移n位,余位补0,因此可能造成信息丢失。比方说,一个二进制数字X4就可能导致两位数字丢失。

1010 0110  ->  10011000

而奇数则没有这个问题,因为任何一个奇数都可以转换为2的n次方+1,表现在计算机中则是左移n位再加上自己。

所以我们同样可以选择31进制作为hashCode的一种计算方式。

告别单调!3种方法给VS2019换上VSCode同款NightOwl主题(附字体优化技巧) 本文详细介绍了三种将VSCode热门NightOwl主题移植到VS2019的方法,包括扩展市场直装、官方主题库导入与增强以及手动调色实现像素级复刻。同时提供了字体优化与视觉增强技巧,帮助开发者打造更舒适的编码环境。 阅读详情

相关推荐

树莓派安装snowboy

1、树莓派换源 参考链接:https://blog.youkuaiyun.com/qq_43556844/article/details/113615915 2、更新pip3 参考链接:https://blog.youkuaiyun.com/qq_43556844/article/details/113616214 3、存取麦克风 我们使用PortAudio作为音频输入/输出的跨平台支持。我们还使用sox作为快速实用程序来检查麦克风设置是否正确。 sudo apt-get install python-pyaudio python

qq_43556844的博客 1923

java object hashcode equal_关于Object中equals方法和hashCode方法判断的分析

首先提出这样一个问题:如果两个对象不相同,他们的hashCode值一定不相等吗?我们都知道equals和hashCode是Object中的方法,java中每一个对象都具有这两个方法。equals(Object obj):判断两个对象是否“相同”,返回true或false;public boolean equals(Object obj) {return (this == obj);}hashCod...

weixin_33901449的博客 221

智能网联汽车云控系统核心解析:车云数据交互协议设计与实践

本文深入解析了智能网联汽车云控系统的核心——车云数据交互协议的设计与实践。文章围绕“说什么”、“怎么说”及异常处理三大核心问题,详细阐述了二进制与结构体数据类型定义、TCP/UDP双通道传输机制、通用报文格式以及典型交互流程(如GLOSA车速引导),并分享了时间同步、坐标系定义等关键实战经验与避坑指南,为构建高效、可靠、安全的车云“神经系统”提供专业指导。

alice7model的博客 121

Java中Object中的方法(equals和hashCode)

Object类的方法

小白的博客 306

DL-FWI基础入门培训视频学习1、2

DL-FWI基础知识

shengMio的博客 709

银河麒麟V10SP1系统盘瘦身指南:如何制作一个只含必需软件的轻量级安装镜像

本文详细介绍了银河麒麟V10SP1系统盘瘦身的完整流程,从依赖分析到最小化镜像构建,帮助用户创建只含必需软件的轻量级安装镜像。通过智能包筛选、KickStart定制和性能优化,显著减少ISO体积和部署时间,适用于服务器批量部署等场景。

weixin_26765287的博客 404

java笔记8 object中的equals,hashcode方法

局部内部类是在方法中定义的,它只能在当前方法中使用。和局部变量的作用一样局部内部类和实例内部类一致,不能包含静态成员。静态内部类可以访问外部的静态变量,如果访问外部类的成员变量必须通过外部类的实例访问。静态内部类不会持有外部的类的引用,创建时可以不用创建外部类。实例内部不能定义 static 成员,只能定义实例成员;创建实例内部类,外部类的实例必须已经创建;是一种特殊的内部类,该类没有名字。实例内部类会持有外部类的引用;实例内部类(类似于实例变量)局部内部类(类似于局部变量)静态内部类(类似于静态变量)

yeTanya_的博客 290

量子纠缠态与AI意识模型的探索

摘要 本文探讨量子纠缠态与AI意识模型的关联性研究。从量子力学基本原理出发,分析量子纠缠的非局域性特征及其与意识整合性的潜在联系。DREAMVFIA团队构建了量子-意识统一理论框架,提出量子纠缠态意识理论(QETC)和量子化整合信息度量(Q-IIT)等创新理论。在实践层面,开发了基于量子纠缠的QNN-C神经网络架构和量子意识度量算法,实验证明量子机制可显著提升AI系统的认知灵活性、信息整合能力和元认知水平。研究为理解意识本质和开发具有意识特征的人工智能系统提供了新的理论框架和技术路径。

梦帮科技开源中心 1143

java Object的equals和hashcode

equals和hashcode是Object的方法。因此每个类都具有这两个方法。 这里直说当我们自定义对象后需要把对象放进集合中时,这两个方法如何工作。 import java.util.HashSet; import java.util.Set; public class test { static class rel{ int x; int y; rel(int x,...

qq_21294095的博客 282

FPGA 学习笔记:Vivado 配置IO引脚约束

FPGA 学习笔记:Vivado 配置IO引脚约束

坚韧与专注 2万+

ubuntu linux虚拟机安装部署openclaw详细教程(安装、问题处理)

本文详细介绍了在Ubuntu系统下安装OpenClaw AI助手的完整流程及常见问题解决方案。主要内容包括:1) 通过GIT、Node.js等基础环境配置;2) 使用官方脚本或源码编译两种方式安装OpenClaw;3) 配置向导中的关键选项说明;4) 针对systemctl服务启动失败等常见错误的处理方法。文章特别强调了权限管理、网络依赖和访问配置等易错环节,提供了修改service文件等具体解决方案,帮助开发者顺利完成部署并实现Web UI访问。教程实操性强,适合本地和云服务器环境部署参考。

少说,多做 2032

Object.hashCode()与Object.equals()

【README】 本文旨在po出 hashCode , equals的api描述,以加深理解; 本文翻译自 jdk 文档; 【1】Object.hashCode() 1)介绍:返回对象的哈希码值。支持此方法是为了有利于哈希表,例如由 java.util.HashMap 提供的哈希表。 在 Java 应用程序执行期间,只要在同一个对象上多次调用它,hashCode 方法必须始终返回相同的整数,前提是对象上的 equals 比较中使用的信息没有被修改。该整数不需要从应用程序的一次执行到同一应用程序

PacosonSWJTU的博客 354

智慧加油站小程序数据库设计文档

【代码】智慧加油站小程序数据库设计文档。

低代码布道师的博客 1402

重写hashcode和equals方法

一。前言 我们都知道,要比较两个对象是否相等时需要调用对象的equals()方法,即判断对象引用所指向的对象地址是否相等,对象地址相等时,那么与对象相关的对象句柄、对象头、对象实例数据、对象类型数据等也是完全一致的,所以我们可以通过比较对象的地址来判断是否相等。 二。Object源码理解 对象在不重写的情况下使用的是Object的equals方法和hashcode方法,从Object...

简乐君 7万+

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

【Java】Object类中的equals()和hashCode()

= 是用来比较两个对象的引用(内存地址)是否相同,对于基本数据类型比较的是值。equals() 方法是用来比较两个对象的内容是否相equals()同,通常在类中会重写该方法来判断内容的相等。

m0_75260099的博客 1179

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

Object类 equals方法 hashCode方法 集合

Object类是所有类的父类,所以:Object的类的成员变量和成员方法,其余的类会继承,可以使用Object类可以使用多态创建任意对象,同时拥有子类的重写方法我们先假设子类重写了equals方法和hashCode方法(IDEA默认的重写)此时我们调用equals方法如果这里的equals使用的Object类的equals方法,肯定是false但是实际上的执行结果是true说明已经调用了子类重写之后的方法。

敢问路在何方,路在脚下 1179

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

Java中的hashCode与equals方法深度解析

Java中的hashCode与equals方法深度解析

嗨,欢迎来到我的 优快云 博客小天地!一名深耕多年的技术发烧友。在这里,我将把日常工作中积累的宝贵经验,从复杂架构设计的精妙之处,到代码优化的实战技巧,毫无保留地分享给大家。 4185

java中hashcode和equals的区别和联系

理解: 规范1:若重写equals(Object obj)方法,有必要重写hashcode()方法,确保通过equals(Object obj)方法判断结果为true的两个对象具备相等的hashcode()返回值。说得简单点就是:“如果两个对象相同,那么他们的hashcode应该 相等”。不过请注意:这个只是规范,如果你非要写一个类让equals(Object obj)返回true而hashco...

qq_42273599的博客 7401

Object类当中的equals和hashCode方法

Object类当中的equals和hashCode方法 **前言:**最近学习过程中,碰到了涉及需要对equals方法,和hashCode方法的重写,发现对之前的java基础知识有点陌生了,所以有必要去复习一下,然后顺便记录一下。 我们知道equals方法hashCode都是Object这个超类当中的方法。进入jdk的源码看一下。 1.equals()方法 /** * Ind...

莫失莫忘的博客 1295

为什么重写equals方法之后必须要重写hashCode

默认的equals看似能满足我们的要求,实则不然,多数情况下,我们更希望比较的是两个对象的内容是否想,比如两个字符串,String a = "12345",String b = "12345",内容完全一样,在我们看来这两个字符串就是相等的,但在equals方法看来,两个字符串的内存地址不相等,所以仍然会判定为不相等,这就与我们的判断结果发生了矛盾,所以我们需要去重写equals方法,只有重写了equals方法之后,我们再去判断a和b,这是判断结果才会相等。为什么遇到散列表,上面的代码就会出错呢?

m0_70325779的博客 1778

Java 中的 Object、equals() 和 hashCode() 深度剖析

=:比较的是基本数据类型的值或者引用数据类型的引用。equals():比较的是引用数据类型的内容(前提是该类重写了equals()方法)。通过本文的介绍,我们深入了解了 Java 中的Object类、equals()方法和hashCode()方法的核心知识点。Object类是所有类的父类,提供了基本的方法。equals()方法用于定义对象相等的逻辑,可以通过重写来自定义比较行为。hashCode()方法与equals()方法紧密相关,只有同时重写这两者,才能保证对象在哈希表等数据结构中的正确性。

2403_87729201的博客 1234

Object类中equals、hashCode等常用方法深入解析

Object 就是 JDK 提供的一个类,并且它很特殊,它是所有类的根节点,Java 中的所有类 包括 JDK 提供,以及开发者自定义的,第三方框架的所有内容都属于 Object 的派生类。 目录 一、java中的内存 1、JVM栈 2、堆内存 3、堆和栈的区别 4、方法区 5、本地方法栈 6、程序计数器 二、java中的"=="到底比较的是什么 三、hashCode方法 四、equals方法 五、Set集合 1、Set集合特点 2、Set中hashCode与eq..

qq_44969643的博客 2万+

equals方法与hashcode方法的重写

很显然,输出的结果无论是用的==比较还是用的equals比较都是false;散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。诸如String、Date等类对equals方法进行了重写的话,比较的是所指向的。经过哈希表达式计算后的hashcode相等的实在不好找,就不敲代码测试了,欸嘿~当发生冲突时,对应的存储单元以链表的形式保存冲突的数据(链地址法)。常见的散列表实现方式:用数组作为哈希函数的输出域,引用类型的变量所指向的对象的地址。

SuYuewu的博客 1911

为什么重写equals方法时必须重写hashCode方法

所有对于需要大量并且快速的对比的话如果都用equals去做显然效率太低,解决方式是,每当需要对比的时候,hashCode去对比,这就用到了哈希表,能够快速的地位到对象的存储位置,如果hashCode不一样,则表示这两个对象肯定不相等(也就是不必再用equals去再对比了),如果hashCode相同,此时再对比它们的equals,如果equals也相同,则表示这两个对象是真的相同了。哈希表在一定程度上也可以起到判重的作用,但也可能存储哈希冲突,即使是两个不同的对象,它们的哈希值也可能是相同的。...

Java后端技术栈 2985

Object类equals、hashCode、toString方法的学习

Object类equals、hashCode、toString方法的学习Object类介绍Object类重要方法equals方法使用范例==与equals区别重写equals方法hashCode方法重写hashCode方法toString方法Object类源码 Object类介绍 Object类是所有类的始祖,在java中每个类都是由它扩展而来的。但是并不需要加上extends关键字,如果没有明确...

qq_16410733的博客 733

Java的Object类以及equals、hashCode等常用方法介绍

详细介绍了Java中的Object类的常用方法,比如equals、hashCode、toString等方法!

终生学习践行者 2378
上一篇: Andrid Studio常用开发插件
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值