【Java】杂项、Equals 和 hashCode

Google Guava实战指南:从基础API到短链接服务完整示例 Java开发中常见的判空、拼接、集合转换等重复代码,不仅耗时而且易错,这时引入Google Guava这类Java工具库可以显著提升编码效率。作为Google开源的核心库,Guava在集合、字符串处理、本地缓存、事件总线、哈希等领域提供了高效API。从不可变集合到Multimap、BiMap等新集合类型,从Joiner与Splitter到Preconditions参数校验,再到Guava Cache解决手写缓存的线程安全和过期策略痛点,以及EventBus实现模块间解耦,配合Hashing生成哈希指纹,都是 阅读详情

equals 和 hashCode含义

equal:判断两个对象是否相等,如果相同,返回true 否则返回false

hashcode: 返回一个int数 Object 默认(内部地址转化为一个数字)

 

两者关系

  • 如果equals(obj)返回true, 那么 hashCode一定返回一样的值

  • 如果equals(obj)返回false, 那么 hashCode 不一定返回一样的值

  • 如果hashCode 返回相同的数,那么 equals 不一定返回true

  • 如果hashCode返回不一样的数,那么equals 一定返回false

 

集合中使用

放入流程

放入散列时候,先比较hashCode, 然后判断equals

HashSet 放入元素

public boolean add(E e) {  
    return map.put(e, PRESENT)==null;  
}

 

HashMap 放入元素

public V put(K key, V value) {  
    if (key == null)  
        return putForNullKey(value);  
    int hash = hash(key.hashCode());  
    int i = indexFor(hash, table.length);  
    for (Entry<K,V> e = table[i]; e != null; e = e.next) {  
        Object k;  
        if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {  
            V oldValue = e.value;  
            e.value = value;  
            e.recordAccess(this);  
            return oldValue;  
        }  
    }  

    modCount++;  
    addEntry(hash, key, value, i);  
    return null;  
}

测试一: 覆盖 equals 不覆盖 hashCode

public class HashCodeTest {  
    public static void main(String[] args) {  
        Collection set = new HashSet();  
        Point p1 = new Point(1, 1);  
        Point p2 = new Point(1, 1);  
  
        System.out.println(p1.equals(p2));  
        set.add(p1);   //(1)  
        set.add(p2);   //(2)  
        set.add(p1);   //(3)  
  
        Iterator iterator = set.iterator();  
        while (iterator.hasNext()) {  
            Object object = iterator.next();  
            System.out.println(object);  
        }  
    }  
}  
  
class Point {  
    private int x;  
    private int y;  
  
    public Point(int x, int y) {  
        super();  
        this.x = x;  
        this.y = y;  
    }  
  
    @Override  
    public boolean equals(Object obj) {  
        if (this == obj)  
            return true;  
        if (obj == null)  
            return false;  
        if (getClass() != obj.getClass())  
            return false;  
        Point other = (Point) obj;  
        if (x != other.x)  
            return false;  
        if (y != other.y)  
            return false;  
        return true;  
    }  
  
    @Override  
    public String toString() {  
        return "x:" + x + ",y:" + y;  
    }  
  
} 

 

输出

true  
x:1,y:1  
x:1,y:1

 

分析

(1)当执行set.add(p1)时(1),集合为空,直接存入集合;

(2)当执行set.add(p2)时(2),首先判断该对象(p2)的hashCode值所在的存储区域是否有相同的hashCode,因为没有覆盖hashCode方法,所以jdk使用默认Object的hashCode方法,返回内存地址转换后的整数,因为不同对象的地址值不同,所以这里不存在与p2相同hashCode值的对象,因此jdk默认不同hashCode值,equals一定返回false,所以直接存入集合。

(3)当执行set.add(p1)时(3),时,因为p1已经存入集合,同一对象返回的hashCode值是一样的,继续判断equals是否返回true,因为是同一对象所以返回true。此时jdk认为该对象已经存在于集合中,所以舍弃。

 

测试二:覆盖hashCode方法,但不覆盖equals方法,仍然会导致数据的不唯一性

class Point {  
    private int x;  
    private int y;  
  
    public Point(int x, int y) {  
        super();  
        this.x = x;  
        this.y = y;  
    }  
  
    @Override  
    public int hashCode() {  
        final int prime = 31;  
        int result = 1;  
        result = prime * result + x;  
        result = prime * result + y;  
        return result;  
    }  
  
    @Override  
    public String toString() {  
        return "x:" + x + ",y:" + y;  
    }  
  
}  

输出

false  
x:1,y:1  
x:1,y:1

分析

(1)当执行set.add(p1)时(1),集合为空,直接存入集合;

(2)当执行set.add(p2)时(2),首先判断该对象(p2)的hashCode值所在的存储区域是否有相同的hashCode,这里覆盖了hashCode方法,p1和p2的hashCode相等,所以继续判断equals是否相等,因为这里没有覆盖equals,默认使用'=='来判断,所以这里equals返回false,jdk认为是不同的对象,所以将p2存入集合。

(3)当执行set.add(p1)时(3),时,因为p1已经存入集合,同一对象返回的hashCode值是一样的,并且equals返回true。此时jdk认为该对象已经存在于集合中,所以舍弃。

 

综合上述两个测试,要想保证元素的唯一性,必须同时覆盖hashCode和equals才行。

(注意:在HashSet中插入同一个元素(hashCode和equals均相等)时,会被舍弃,而在HashMap中插入同一个Key(Value 不同)时,原来的元素会被覆盖。)

测试三 内存泄漏问题

public class HashCodeTest {  
    public static void main(String[] args) {  
        Collection set = new HashSet();  
        Point p1 = new Point(1, 1);  
        Point p2 = new Point(1, 2);  
  
        set.add(p1);  
        set.add(p2);  
          
        p2.setX(10);  
        p2.setY(10);  
          
        set.remove(p2);  
  
        Iterator iterator = set.iterator();  
        while (iterator.hasNext()) {  
            Object object = iterator.next();  
            System.out.println(object);  
        }  
    }  
}  
  
class Point {  
    private int x;  
    private int y;  
  
    public Point(int x, int y) {  
        super();  
        this.x = x;  
        this.y = y;  
    }  
  
  
    public int getX() {  
        return x;  
    }  
  
  
    public void setX(int x) {  
        this.x = x;  
    }  
  
  
    public int getY() {  
        return y;  
    }  
  
  
    public void setY(int y) {  
        this.y = y;  
    }  
  
  
    @Override  
    public int hashCode() {  
        final int prime = 31;  
        int result = 1;  
        result = prime * result + x;  
        result = prime * result + y;  
        return result;  
    }  
  
  
    @Override  
    public boolean equals(Object obj) {  
        if (this == obj)  
            return true;  
        if (obj == null)  
            return false;  
        if (getClass() != obj.getClass())  
            return false;  
        Point other = (Point) obj;  
        if (x != other.x)  
            return false;  
        if (y != other.y)  
            return false;  
        return true;  
    }  
  
  
    @Override  
    public String toString() {  
        return "x:" + x + ",y:" + y;  
    }  
  
}  

结果

x:1,y:1  
x:10,y:10

 

分析

假设p1的hashCode为1,p2的hashCode为2,在存储时p1被分配在1号桶中,p2被分配在2号筒中。这时修改了p2中与计算hashCode有关的信息(x和y),当调用remove(Object obj)时,首先会查找该hashCode值得对象是否在集合中。假设修改后的hashCode值为10(仍存在2号桶中),这时查找结果空,jdk认为该对象不在集合中,所以不会进行删除操作。然而用户以为该对象已经被删除,导致该对象长时间不能被释放,造成内存泄露。解决该问题的办法是不要在执行期间修改与hashCode值有关的对象信息,如果非要修改,则必须先从集合中删除,更新信息后再加入集合中。

总结

1.hashCode是为了提高在散列结构存储中查找的效率,在线性表中没有作用。

2.equals和hashCode需要同时覆盖。

3.若两个对象equals返回true,则hashCode有必要也返回相同的int数。

4.若两个对象equals返回false,则hashCode不一定返回不同的int数,但为不相等的对象生成不同hashCode值可以提高哈希表的性能。

5.若两个对象hashCode返回相同int数,则equals不一定返回true。

6.若两个对象hashCode返回不同int数,则equals一定返回false。

7.同一对象在执行期间若已经存储在集合中,则不能修改影响hashCode值的相关信息,否则会导致内存泄露问题。

 

原文:https://blog.youkuaiyun.com/haobaworenle/article/details/53819838

 

S7-1200PLC 与温控仪表Modbus RTU通信 硬件:cpu 1214C 目的:通过Modbus RTU协议,实现对温控仪表的控制 软件:Portal V14SP1 阅读详情

相关推荐

基于YOLOv8和PaddlepaddleOCR的微信截图聊天记录提取

本文提出了一种基于YOLOv8和PaddleOCR的微信聊天记录提取方法。首先使用YOLOv8n模型分割出聊天气泡(针对深浅色模式分别训练),通过合成数据集增强模型鲁棒性,召回率达0.995。随后采用PP-OCRv5进行文本识别,利用坐标匹配将气泡内文本送入识别队列,短长文本平均置信度分别>0.98和>0.95。文中特别强调了PaddleOCR不同版本的输出格式差异及适配方案,建议使用3.0+版本。该方法有效解决了直接OCR识别易受干扰的问题,通过气泡分割+文本定位的两阶段策略显著提升了识别准确

2401_87383958的博客 2356

CTF Web实战进阶:三层渗透法与黑客思维构建

Web安全渗透测试是网络安全领域的核心技能,其本质在于理解系统架构并发现其脆弱性。从原理层面看,渗透测试遵循从信息搜集到漏洞利用的完整生命周期,涉及对网络协议、应用逻辑和系统组件的深入分析。在技术价值上,掌握系统化的测试方法能显著提升漏洞挖掘效率与防御能力,尤其适用于CTF竞赛、红蓝对抗和实际安全评估等场景。本文聚焦于CTF Web实战,通过整合漏洞探测与链式利用等关键技术,系统阐述如何构建从信息搜集、漏洞验证到边界突破的三层渗透体系,并强调工具链整合与自动化脚本在实战中的应用,帮助安全从业者及CTF选手建

shirlly 417

vit的cam和注意力图: VIT模型的可解释性

VIT的热力图怎么画

YI_SHU_JIA的博客 1万+

【Java杂项】equals 与 hashCode 为什么必须一起重写?从 HashMap 原理到可变 key 避坑

本文从 Java 对象相等契约出发,讲清 equals() 与 hashCode() 为什么必须一起重写:HashMap/HashSet 会先用 hashCode 定位桶,再用 equals 判断逻辑相等。文章结合 BadStudent、MutableStudent、String key、继承对称性和可变 key 等示例,梳理哈希冲突、逻辑内存泄漏和生产级 key 设计边界。

超级苦力怕的博客 1449

调用D3D11硬解码和渲染VideoProcessor版本

在https://blog.youkuaiyun.com/robothn/article/details/78781321一文中使用shader来显示FFMPEG硬解码后的YUV420P,本文调用D3D11的videoprocessor来进行图像空间变换和尺寸变换,取得了较好的效果。 1.初始化D3D11设备、videodevice等数据结构 FFMPEG调用D3D11硬解码,获取其对应的device,videodevice。。。 FFMPEG使用av_hwdevice_find_type_by_name调用D3d11

zlyadvocate的博客 9285

Jetson系列目标检测及推流

使用硬件编码,gstreamer推rtsp流至平台

xiao__run的博客 2710

【Java杂项】HashMap 为什么不能用可变对象当 key?从 get 返回 null 到集合污染

本文围绕 Java `HashMap` 中“可变对象能不能当 key”展开,用最小代码解释为什么修改 key 字段后 `get()` 可能返回 `null`。文章进一步分析桶定位、`hashCode()`、`equals()`、同引用比较、跨对象相等性污染、逻辑重复 key 和 `remove()` 失败等工程问题,并给出 `entrySet()` 遍历清理、重建 Map、`final class`、`record`、Lombok `@Value` 等防御性设计建议。

超级苦力怕的博客 3944

【教程4>第4章>第12节】通过FPGA实现基于FFT变换的频偏估计和补偿

基于FFT变换的频偏估计和补偿,其基本原理如下:而频偏补偿的目的是将频偏后的信号频谱移回原来的位置。

FPGA/MATLAB学习教程/源码/项目合作开发 882

Java杂项记录

Java知识点汇总以及常见面试题 “==”和equals()的区别 ==比较基本数据类型,比较的是值是否相等,比较引用数据类型时是地址值是否相等,地址值相等代表引用同一个对象,返回true。 equals(),在Object类中比较的是地址值是否相等,而在其他类重写后,根据重写的equals()方法进行判断。 构造方法能不能重写或者重载 构造器不能被重写,但是能被重载。 基本数据类型 类型 字节 位数 取值范围 默认值 byte 1 8 -128~127 0 short 2 16 -

一条老狗的博客 1507

告警不是闹钟:AI 如何把告警过滤成真正的“求救信号”?

告警不是闹钟:AI 如何把告警过滤成真正的“求救信号”?

Echo_Wish 242

从 VL02N 拣配到 ABAP 自动化,读懂 SD_DELIVERY_UPDATE_PICKING 的位置和风险

文章摘要:SAP SD模块中,SD_DELIVERY_UPDATE_PICKING函数模块用于处理出库交货单的拣配确认,更新交货项目的拣配数量。该函数适用于未启用WM/EWM的传统SD流程,能确保拣配状态与标准交货处理逻辑同步,比直接修改数据库更安全。但在S/4HANA Cloud等新环境中,应优先使用API_OUTBOUND_DELIVERY_SRV等公开发布接口。使用该函数时需注意参数完整性和按交货单整体处理的原则,避免逐项提交导致的数据不一致问题。(149字)

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 245

个人笔记(杂项)

1

weixin_46388053的博客 172

uniapp - 实现手机端H5网页直播功能效果,拿到后端推流地址或播放资源后进行前端的流畅播放和画面展示功能,uniapp实时推流/拉流直播系统详细教程(提供完整示例代码,一键复制开箱即用!)

uniapp,h5网页,手机端H5网页,uniapp h5直播功能页面,uniapp直播实时推送显示,uniapp h5直播怎么做,怎么使用uniapp去实现移动端手机H5直播,h5 vue+uniapp怎么做直播,uniapp中使用videojs构建H5直播播放器,uniappH5端怎么实现直播推流,uniapp如何实现直播,直播聊天功能,h5平台端直播用什么插件,uniapp手机网页直播用什么组件插件播放器,uniapp手机H5直播播放器详细教程,直播项目,怎么使用vue+uniapp怎么做H5实时直播

✅ 精选推荐文章 8792

面试汇总-Java基础-杂项(持续更新)

​​​ 除了double和long之外,对其他基本数据类型的操作都是原子性的。而对于double和long,两种类型都是8个字节64位,在32位操作系统的环境下,一次操作只能读取32位,无法一次性读取double和long数据,多线程环境下可能导致数据读写错误。...

weixin_37672801的博客 459

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

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

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

java基础数据结构

1.equals 和== equals :底层实现也是调用的== 如果想要只比较值就要重写equals方法 == : 引用数据类型:比较的是地址值 基本数据类型比较的是数值(不一定类型相同2.0==2) String s1 = new String("zs"); String s2 = new String("zs"); System.out.println(s1 == s2); //false 因为都是new的地址不一样 String s3 ...

Culprit的博客 65

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

【JAVA零散知识点】

在Java面试中可能会遇到的一些知识点。

Stdio_QU的博客 211

开发工具之Eclipse(三)

1. 2. 3. 4.

Linda的专栏 526

java--面向对象

杂项 1.在一个源文件中,只能有一个公共类,但可有任意数目的非公共类。文件名必须与public类的名字匹配。 2.多个源文件,javac xxx.java,只指定包含main的源文件,会自动编译关联的其他源文件。java xxx,xxx为包含main的源文件不含后缀名。 3.每个类都可有一个main方法用于此类单元测试,运行进程时,采用指定名称类的main作为进程的main。 4.类型 - 基本数据类型 - 对象 ...

x13262608581的博客 625

%I64d 和%lld 的区别

//为了和DSP兼容,TSint64和TUint64设置成TSint40和TUint40一样的数 //结果VC中还是认为是32位的,显然不合适 //typedefsignedlongintTSint64; //typedefunsignedlongintTUint64; //ANSIC中规定longlong才能表示64位 ...

ZLei 3万+

【C++】优先队列

STL之priority_queue【转】 STL之优先队列 原本以为priority_queue很简单,才知道原来懂的只是最简单的形式。 头文件:#include<queue> 优先队列,也就是原来我们学过的堆,按照自己定义的优先级出队时。默认情况下底层是以Vector实现的heap。 既然是队列,也就只有入队、出队、判空、大小的操作,...

ZLei 589

【Java】方法的重写和方法的重载

方法的重写和方法的重载是两个不同的概念: 方法的重载是在同一个类中,定义同名函数,通过参数类型和个数的不同来区分不同的函数, 方法的重写是在父类和子类中, 子类通过定义和父类函数同名的函数可以覆盖父类的方法, 这称为函数的重写 ...

ZLei 569

【JAVA】jave正则表达式

Java正则表达式 一:什么是正则表达式 1.定义:正则表达式是一种可以用于模式匹配和替换的规范,一个正则表达式就是由普通的字符(例如字符a到z)以及特殊字符(元字符)组成的文字模式,它 用以描述在查找文字主体时待匹配的一个或多个字符串。正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行匹配。 2.用途: 字符串匹配(字符匹配) 字符串查找 字符串替换 字符串...

ZLei 488

【Java】基础、Final 关键字

final 修饰符, 表示不可改变的常量1.final 修饰成员变量的时候初始化的地方有两个, 一个是在定义时候初始化(构造器或者非静态初始化块), 一个是在构建对象时候初始化,只能在一个地方初始化,并且在初始化之后不可以改变。 2.final 修饰类变量的时候可以在定义时候初始化,也可以在静态初始化块中定义初始化 只能在一个地方初始化,并且在初始化之后不可以改变。 3.final 修饰局部变量可以

ZLei 417

【Java】JVM(三)、Java垃圾收集器

一、Minor GC、Major GC 和 Full GC   Minor GC:清理新生代空间,当Eden空间不能分配时候引发Minor GC   Major GC:清理老年代空间   Full GC:清理Java堆空间 二、新生代垃圾收集器   1. Serial 收集器      线程:单线程收集器,   算法:新生代标记复制,老年代标记整理   缺点:在进行垃圾...

ZLei 208

【Java】JVM(四)、虚拟机参数配置

1.-Xms20M JVM启动时候的内存大小为20M 2.-Xmx20M JVM内存最大值是20M 将其与Xms大小一致可以避免JVM内存自动扩展 3. -Xss128K 表示可以设置虚拟机栈大小为128K 4. -Xoss128K 表示设置本地方法栈的大小为128K(HotSpot不区分虚拟机栈和方法栈) 5. -...

ZLei 206

【Java】JavaIO(二)、节点流

一、InputStream & outputStream   Java字节流主要是以InputStream (输入流),outputStream(输出流)为基类,本身是抽象类不能创建实例,但是是字节流的基类,所以方法都可以使用,主要的方法有   InputStream: 1 int read();读取单个字节 2 int read(byte[] b); 最多读取b.length 字...

ZLei 204
上一篇: 【Java】JVM(六)虚拟机字节码执行引擎
下一篇: 【索引】索引的介绍与优化
三生石1103
博客等级 码龄12年 16粉丝 87原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值