equals()和hashCode()

HashMap是Java集合框架中的一个非常重要的组成部分,它提供了基于键值对的快速查找功能。在Java中,HashMap的底层实现是基于数组和链表或红黑树的结合体,具体取决于元素的数量和散列冲突的情况。以下是HashMap的一些关键概念和底层原理:

  1. 数组作为主存储结构:
    HashMap内部维护了一个数组,数组的每个位置(称为桶或槽)可以存放一个链表或红黑树的根节点。数组的大小通常是2的幂次方,这样可以利用位操作来提高散列计算的效率。

  2. 散列函数:
    当插入或查找元素时,HashMap会使用键的hashCode()方法来计算其散列值。这个散列值会被进一步处理以确定元素在数组中的位置。处理的方式通常包括取模运算或位与运算(当数组大小为2的幂时)。

  3. 解决散列冲突: 散列冲突是指不同的键映射到了数组的同一位置上。HashMap通过在数组的每个位置上使用链表或红黑树来解决冲突。在Java 8及以后的版本中,当链表长度达到一定阈值(默认为8)时,链表会被转换成红黑树以提高查找效率。

  4. 负载因子和动态扩容: 负载因子是HashMap的一个重要参数,它定义了数组的填充程度,即元素数量与数组大小的比例。当HashMap的大小超过数组大小与负载因子的乘积时,HashMap会自动进行扩容,将数组大小翻倍,并重新散列所有元素

  5. 线程安全性: 标准的HashMap是非线程安全的。如果多个线程同时修改HashMap,可能会导致数据不一致或其他错误。为了保证线程安全,可以使用Collections.synchronizedMap()方法或ConcurrentHashMap。

  6. 初始化和默认参数: HashMap可以通过构造函数指定初始容量和负载因子。如果没有指定,默认的初始容量是16,负载因子是0.75。
    理解HashMap的底层原理对于优化代码性能和避免常见的编程陷阱非常重要。例如,了解散列冲突和负载因子可以帮助你选择合适的初始容量和负载因子,从而减少不必要的扩容操作。

hashmap与equals和hashcode的关系

HashMap在Java中是一种基于哈希表的数据结构,它依赖于对象的hashCode()和equals()方法来正确地存储和检索数据。HashMap的高效性很大程度上取决于这两个方法的正确实现。下面详细解释它们之间的关系:

  1. hashCode()方法:
    1、hashCode()方法返回一个整数,这个整数被称为对象的哈希码。
    2、在HashMap中,当你添加一个键值对时,HashMap会调用键对象的hashCode()方法来计算一个哈希值,这个哈希值用于确定键值对在内部数组中的位置。
    3、如果两个对象的hashCode()返回相同的值,这并不意味着这两个对象相等,但是,如果equals()方法返回true,则它们的hashCode()必须返回相同的结果。

  2. equals()方法:
    1、equals()方法用于比较两个对象是否相等。
    2、当HashMap需要确定两个键是否相等时,它会调用equals()方法。
    3、如果两个键的equals()方法返回true,那么HashMap认为这两个键代表同一个键,因此它们应该映射到同一个值。

  3. 一致性原则:
    1、对于HashMap而言,hashCode()和equals()方法的一致性是非常重要的。这意味着,如果两个对象相等(即equals()返回true),那么它们的hashCode()必须返回相同的值。
    2、反过来,如果hashCode()返回相同的值,equals()不一定返回true,因为哈希碰撞是可能发生的,即不同的对象可能有相同的哈希码。

  4. 重写指导原则:
    1、当你重写一个类的equals()方法时,你也应该重写hashCode()方法,以确保一致性。
    2、通常情况下,hashCode()和equals()方法应该基于对象的那些用来判断相等性的属性来实现。

  5. 性能影响:
    1、如果hashCode()方法设计得不好,比如返回常量或者相似的对象返回不同的哈希值,这会导致HashMap的性能下降,因为这会增加链表的长度,降低查找效率。
    2、同样,如果equals()方法执行效率低,也会影响HashMap的整体性能,因为它在查找过程中会被频繁调用。
    综上所述,HashMap的正确性和性能在很大程度上依赖于键对象的hashCode()和equals()方法的正确实现。如果这些方法没有按照上述规则实现,HashMap的行为可能会出乎意料,甚至导致严重的性能问题。

Java中,如果你重写了equals()方法,那么几乎总是需要重写hashCode()方法,这是因为equals()hashCode()方法之间存在着一种约定,这种约定确保了对象在基于哈希的数据结构(如HashMapHashSet等)中的行为是一致的。
根据Java官方文档,当你重写equals()方法时,应该遵循以下原则:
1、如果x.equals(y)返回true,那么x.hashCode()和y.hashCode()必须返回相同的值。
2、如果x.equals(y)返回false,则x.hashCode()和y.hashCode()不必相同,但最好不同,以减少哈希冲突。
重写hashCode()方法的原因有以下几点:1. 一致性:当两个对象根据equals()方法被认为是相等的,它们的哈希码必须相同。这确保了在哈希表中查找对象时能够找到正确的条目。2. 减少哈希冲突:即使两个对象不相等,它们也可能有相同的哈希码。良好的hashCode()实现可以尽量减少这种情况的发生,从而提高基于哈希的数据结构的性能。3. 性能:当对象被用作HashMapHashSet的键时,hashCode()方法的性能对整体应用的性能有很大影响。如果hashCode()方法效率低下,每次访问都会产生额外的开销。4. 数据结构的正确性:在某些数据结构中,如HashMapequals()hashCode()的正确实现是数据结构正确工作和避免运行时错误的必要条件。
因此,如果你在自定义类中重写了equals()方法,你应该同时重写hashCode()方法,以确保你的类能够在基于哈希的数据结构中正常工作。正确的做法是,hashCode()方法应该基于equals()方法中用于判断相等性的那些字段来计算哈希值。这样可以确保当两个对象根据equals()方法相等时,它们的hashCode()也会相等,满足了哈希数据结构的要求。

使用equals()怎么重写hashcode()

在Java中,如果你已经重写了equals()方法,那么为了保持equals()和hashCode()方法的一致性,你也应该重写hashCode()方法。以下是一个步骤指南,说明如何重写hashCode()方法:

步骤 1: 确定equals()方法中的关键字段

首先,你需要确定哪些字段是用于equals()方法中判断对象相等的关键字段。这些字段应该是决定对象状态的不变属性。

步骤 2: 计算哈希码

接下来,基于这些关键字段来计算哈希码。你可以使用以下策略之一:

使用Objects.hash()方法

这是最简单且推荐的做法,因为它可以处理null值并且提供了合理的分布。

@Override
public int hashCode() {return Objects.hash(field1, field2, field3);
}
手动计算哈希码

如果你想要手动控制哈希码的计算,可以使用以下公式:

@Override
public int hashCode() {int result = 17;result = 31 * result + (field1 != null ? field1.hashCode() : 0);result = 31 * result + (field2 != null ? field2.hashCode() : 0);result = 31 * result + (field3 != null ? field3.hashCode() : 0);return result;
}

在这个例子中,我们使用了质数31来混合哈希码值,这是一个常用的技巧,因为质数可以减少哈希值的碰撞。

步骤 3: 确保一致性

确保你的hashCode()方法和equals()方法保持一致,即如果两个对象根据equals()方法相等,它们的hashCode()方法也应该返回相同的值。

示例

假设你有一个Person类,其中firstName和lastName字段用于判断对象是否相等:

public class Person {private String firstName;private String lastName;public Person(String firstName, String lastName) {this.firstName = firstName;this.lastName = lastName;}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Person person = (Person) o;return Objects.equals(firstName, person.firstName) &&Objects.equals(lastName, person.lastName);}@Overridepublic int hashCode() {return Objects.hash(firstName, lastName);}
}

在这个例子中,equals()和hashCode()方法都基于firstName和lastName字段。这样可以确保equals()和hashCode()方法的一致性,使Person对象能够在基于哈希的数据结构中正确工作。

注意事项

1、确保hashCode()方法的实现不会抛出NullPointerException,除非equals()方法在相同条件下也会抛出。
2、尽量避免使用类变量或可变状态来计算哈希码,因为这可能导致不一致的行为。
3、如果对象的状态在创建后可以改变,考虑使用防御性拷贝或其他机制来确保hashCode()方法的稳定性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/874526.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用C#手搓Word插件

WordTools主要功能介绍 编码语言:C#【VSTO】 1、选择 1.1、表格 作用:全选文档中的表格; 1.2、表头 作用:全选文档所有表格的表头【第一行】; 1.3、表正文 全选文档中所有表格的除表头部分【除第一行部分】 1.…

java面向对象进阶篇--《多态》

目录 一、前言 二、认识多态 方法重写(Override): 方法重载(Overload): 示例: Person类(父类) Administrator(子类) Student(子…

docker搭建ES 8.14 集群

参考:【docker搭建es8集群kibana】_docker 安装生产级 es 8.14 集群-CSDN博客 1、之前已搭建一台单机版的dockerES集群 参见 Elasticsearch docker 安装_docker 安装es8.14.3-CSDN博客 2、现在需要重新搭建为docker ES集群 准备新搭建3个点 一、准备工作 提前开…

Android SurfaceFlinger——创建EGLContext(二十六)

前面文章我们获取了 EGL 的最优配置,创建了 EGLSurface 并与 Surface 进行了关联,然后还需要获取 OpenGL ES 的上下文 Context,这也是 EGL 控制接口的三要素(Displays、Contexts 和 Surfaces)之一。 1)getInternalDisplayToken:获取显示屏的 SurfaceControl 令牌(Token…

构建网络安全之盾:应对“微软蓝屏”教训的全面策略

✨✨ 欢迎大家来访Srlua的博文(づ ̄3 ̄)づ╭❤~✨✨ 🌟🌟 欢迎各位亲爱的读者,感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢,在这里我会分享我的知识和经验。&am…

深度学习模型Transformer结构

Transformer结构是一种基于自注意力(Self-Attention)机制的深度学习模型,最初由Vaswani等人在2017年的论文《Attention Is All You Need》中提出,用于解决自然语言处理(NLP)领域的任务,如机器翻…

MySQL --- 库的操作

一、创建数据库 create database [ if not exists ] 数据库名; // []中的为可选项 在创建库时,也可以指定数据库采用的字符集(character set)和数据库字符集的校验规则(collate) (当我们创建数据库没有指定字符集和校验规则时,系统使用默认字符集&#x…

【复习】软件工程

软件危机是指在计算机软件的开发和维护过程中所遇到的一系列严重问题。 典型表现: 开发成本和进度的估计常常很不准确 用户对已完成的软件系统不满意,闭门造车 软件质量(quality)不可靠 软件常常是不可维护的 软件产品供不应…

css技巧混合模式

看上面这个神奇的效果,文字在黑色背景里面显示为白色,而在白色的背景里面显示为黑色,这就是文字智能适配背景。 看到这样的需求,大多数人第一时间想到的是,文字元素有两个,是完全重叠的两层,一…

Facebook在内容创作中的新策略与机会

随着社交媒体的不断发展,内容创作已经成为了平台吸引和留住用户的核心竞争力。Facebook作为全球最大的社交平台之一,不断调整和优化其内容创作策略,以适应用户需求的变化和技术的进步。本文将深入探讨Facebook在内容创作中的新策略与机会&…

最新全流程Python编程、机器学习与深度学习实践技术应用

近年来,人工智能领域的飞速发展极大地改变了各个行业的面貌。当前最新的技术动态,如大型语言模型和深度学习技术的发展,展示了深度学习和机器学习技术的强大潜力,成为推动创新和提升竞争力的关键。特别是PyTorch,凭借其…

考研复习7月进度严重滞后?

宇哥说:来不及了! 因为基础30讲和强化36讲,加起来已经快300小时了。 所以,必须换个思路: 不看课行吗? 大多数人7月的情况是这样的: 1. 听完线代,高数知识点忘得差不多了&#xf…

React/Vue项目解决跨域的方法

在Vue项目中,一般使用以下几种方法来解决跨域问题: 一、代理(Proxy): 通过Vue的配置文件(vue.config.js)中的devServer选项,可以设置代理来解决跨域问题。通过将请求发送到同一域名…

JMeter接口测试-3.断言及参数化测试

1. 断言 JMeter官方断言(Assertion)的定义 用于检查测试中得到的响应数据是否符合预期,用于保证测试过程中的数据交互与预期一致 断言的目的: 一个取样器可以添加多个不同形式的断言,根据你的检查需求来添加相应的…

自动驾驶系列—智能巡航辅助功能中的路口通行功能介绍

自动驾驶系列—智能巡航辅助功能中的车道中央保持功能介绍 自动驾驶系列—智能巡航辅助功能中的车道变换功能介绍 自动驾驶系列—智能巡航辅助功能中的横向避让功能介绍 自动驾驶系列—智能巡航辅助功能中的路口通行功能介绍 文章目录 2. 功能定义3. 功能原理4. 传感器架构5. 实…

Java语言程序设计基础篇_编程练习题**15.18(使用鼠标来移动一个矩形)

**15.18(使用鼠标来移动一个矩形) 请编写一个程序显示一个矩形。可以使用鼠标单击矩形内部并且拖动(即按住鼠标移动)矩形到鼠标的位置。鼠标点成为矩形的中央习题思路: 新建一个面板Pane(),新建一个Rectangle() 为Rectangle注册…

【北京迅为】《i.MX8MM嵌入式Linux开发指南》-第三篇 嵌入式Linux驱动开发篇-第三十九章 Linux MISC驱动

i.MX8MM处理器采用了先进的14LPCFinFET工艺,提供更快的速度和更高的电源效率;四核Cortex-A53,单核Cortex-M4,多达五个内核 ,主频高达1.8GHz,2G DDR4内存、8G EMMC存储。千兆工业级以太网、MIPI-DSI、USB HOST、WIFI/BT…

web每日一练

每日一题 每天一题罢了。。 ctfshow内部赛签到 扫到备份文件 login.php <?php function check($arr){ if(preg_match("/load|and|or|\||\&|select|union|\|| |\\\|,|sleep|ascii/i",$arr)){echo "<script>alert(bad hacker!)</script>&q…

微服务和VUE入门教程(16): zuul 熔断

1. 前言 在开发工程中&#xff0c;我们发现当一个微服务挂掉之后&#xff0c;如果我们访问此微服务的接口&#xff0c;zuul也会挂掉。因为zuul负责分配请求&#xff0c;当目标微服务挂掉之后&#xff0c;zuul便找不到目标微服务&#xff0c;因为我们需要设置一个熔断&#xff0…

电机调速控制模块说明文档

电机调速控制模块说明文档 图1-1总览图片 概述本电机控制模块是用于精确控制直流无刷电机运行、以及转速的关键组件&#xff0c;它能够实现对电机的启动、停止、调速、转向等操作&#xff0c;并提供多种保护功能&#xff0c;以确保电机的安全稳定运行。 驱动方式&#xff1a;…