为什么你的HashSet不去重?彻底搞懂对象哈希计算与内存地址的关系

第一章:HashSet去重失效的常见现象

在Java开发中,HashSet 是基于哈希表实现的集合类,常用于存储不重复的元素。然而,在实际使用过程中,开发者常常遇到“去重失效”的问题,即本应唯一的对象被重复添加到集合中。

重写规则未遵守

HashSet 判断元素是否重复依赖于对象的 equals() 和 hashCode() 方法。若自定义类未正确重写这两个方法,会导致逻辑上相等的对象被视为不同元素。 例如,以下代码展示了未重写方法导致去重失败的情况:

class Person {
    String name;
    int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

// 测试代码
Set<Person> set = new HashSet<>();
set.add(new Person("Alice", 25));
set.add(new Person("Alice", 25)); // 本应去重,但实际会添加两次
System.out.println(set.size()); // 输出:2
上述代码中,两个 Person 对象内容相同,但由于未重写 hashCode() 和 equals(),它们的哈希码不同,HashSet 认为是不同对象。

常见原因归纳

  • 未重写 hashCode() 和 equals() 方法
  • 只重写了其中一个方法,导致行为不一致
  • 重写逻辑错误,例如比较了可变字段但未考虑哈希一致性
为避免此类问题,建议在自定义类中始终同时重写这两个方法。推荐使用IDE生成或借助工具类(如Apache Commons Lang中的 EqualsBuilder 和 HashCodeBuilder)。
场景是否去重成功说明
未重写任何方法否使用默认引用比较
仅重写 equals否hashCode 不一致导致无法定位桶位置
同时重写 equals 和 hashCode是满足集合去重契约

第二章:HashSet去重机制的核心原理

2.1 哈希表结构与元素存储逻辑

哈希表是一种基于键值对(Key-Value)存储的数据结构,通过哈希函数将键映射到数组的特定位置,实现平均时间复杂度为 O(1) 的高效查找。
核心结构组成
一个典型的哈希表由数组和链表(或红黑树)构成,数组作为桶(bucket)存放数据,冲突时使用链表法解决。当链表长度超过阈值(如 Java 中为 8),则转换为红黑树以提升性能。
元素存储流程
  • 计算键的哈希值:hash = hashFunction(key)
  • 映射到数组索引:index = hash % arraySize
  • 若发生冲突,则在对应链表中插入新节点
// 简化版哈希表节点定义
type Node struct {
    Key   string
    Value interface{}
    Next  *Node
}
上述代码定义了链地址法中的节点结构,Next 指针用于处理哈希冲突,形成单向链表。每个桶存储链表头节点,实现动态扩容与高效检索。

2.2 hashCode()方法的作用与实现规范

核心作用解析
hashCode() 方法主要用于提升哈希表(如 HashMap、HashSet)的检索效率。它返回一个整型散列码,标识对象的内存特征,使得集合类能快速定位对象存储位置。
实现规范与约定
根据 Java 规范,若两个对象通过 equals() 判定相等,则它们的 hashCode() 必须相同。反之则不必然。这一约定保障了哈希结构的一致性。
  • 在程序执行期间,同一对象多次调用 hashCode() 应返回相同值(前提是影响 equals 的字段未修改)
  • 不同对象的 hashCode() 尽量分散,减少哈希冲突
public int hashCode() {
    int result = 17;
    result = 31 * result + this.id;
    result = 31 * result + (this.name != null ? this.name.hashCode() : 0);
    return result;
}
上述代码采用质数乘法累积字段哈希值,是一种经典实现方式。其中 31 能被 JVM 优化为位运算,提升性能。该策略有效降低冲突概率,符合散列函数设计原则。

2.3 equals()方法在去重中的关键角色

在Java集合操作中,`equals()`方法是实现对象去重的核心机制。当使用`HashSet`或`ArrayList`等容器时,系统通过`equals()`判断两个对象是否逻辑相等。
重写equals()的必要性
默认的`equals()`仅比较引用地址,需根据业务字段重写以实现内容比对。例如:

@Override
public boolean equals(Object obj) {
    if (this == obj) return true;
    if (!(obj instanceof User)) return false;
    User user = (User) obj;
    return Objects.equals(id, user.id) && Objects.equals(name, user.name);
}
上述代码确保ID与姓名相同的用户被视为同一对象,从而在添加至Set时触发去重。
equals()与hashCode()契约
  • 若两个对象相等,其hashCode必须相同
  • 重写equals()时必须同步重写hashCode()
该契约保障哈希集合(如HashMap、HashSet)的正确性与性能。

2.4 哈希冲突处理与链表/红黑树转换

在哈希表实现中,哈希冲突不可避免。主流解决方案包括链地址法和开放寻址法,其中链地址法最为常见。Java 的 `HashMap` 即采用该方法:每个桶位存储一个链表,用于容纳哈希值相同的元素。
链表转红黑树的优化策略
当某个桶中的链表长度超过阈值(默认为8),且哈希表容量大于64时,链表将转换为红黑树,以降低查找时间复杂度从 O(n) 到 O(log n)。

static final int TREEIFY_THRESHOLD = 8;
static final int MIN_TREEIFY_CAPACITY = 64;
上述参数控制了结构转换的时机,避免在小容量或短链表场景下过早引入红黑树带来的额外开销。
转换过程与性能权衡
转换由内部方法 `treeifyBin()` 触发,若容量不足则优先扩容而非转树。此机制平衡了空间与时间效率,体现了动态数据结构的自适应设计思想。

2.5 添加元素时的去重流程源码剖析

在集合类数据结构中,添加元素时的去重机制是保障数据唯一性的核心逻辑。以 Java 中的 `HashSet` 为例,其底层依赖 `HashMap` 实现,调用 `add(E e)` 方法时,实际是将元素作为 key 存入 map。
关键源码分析

public boolean add(E e) {
    return map.put(e, PRESENT) == null;
}
其中 `PRESENT` 是一个空的占位对象。当 put 操作返回 null,说明此前无此 key,插入成功;否则视为重复。
去重判定流程
  • 计算元素的 hashCode() 值定位桶位置
  • 若发生哈希冲突,则通过 equals() 方法逐个比较链表或红黑树中的节点
  • 只有 hash 值相等且 equals 返回 true 才判定为重复元素
该机制依赖用户正确重写 `hashCode()` 与 `equals()` 方法,否则可能导致去重失效或性能退化。

第三章:对象哈希计算与内存地址的关系

3.1 默认hashCode()是否等于内存地址?

在Java中,`Object`类的`hashCode()`方法默认实现常被误解为直接返回对象的内存地址。实际上,HotSpot虚拟机并未直接使用内存地址作为哈希码,而是基于对象指针或特定算法生成一个与内存位置相关的唯一整数。
默认实现机制
JVM通常采用一种称为“偏向哈希码”的策略,首次调用时通过随机数或线程栈信息计算并缓存结果,避免频繁访问底层地址。
代码示例与分析

public class HashCodeExample {
    public static void main(String[] args) {
        Object obj = new Object();
        System.out.println(obj.hashCode()); // 输出一个整数值
    }
}
该代码输出的哈希码并非内存地址本身,而是由JVM内部的多项式散列函数计算得出,确保分布均匀且性能高效。
  • 哈希码不保证唯一性,但应尽量避免冲突;
  • 同一对象多次调用返回相同值(前提是未重写);
  • 不同JVM实现可能采用不同算法。

3.2 JVM如何生成对象的默认哈希值

在Java中,每个对象都继承自`Object`类,其`hashCode()`方法由JVM底层实现。默认情况下,该值并非随机生成,而是基于对象的内存地址或特定算法计算得出。
哈希值生成机制
JVM根据运行时配置选择不同的哈希策略,可通过`-XX:hashCode=n`参数控制:
  • 0:随机数生成(默认)
  • 1:基于对象指针异或移位
  • 2:恒定值1(用于测试)
  • 3:自增序列
代码示例与分析
Object obj = new Object();
System.out.println(obj.hashCode()); // 输出如: 12677476
上述代码调用的是JVM内置实现。以OpenJDK为例,若采用策略1,实际使用对象指针经过多轮异或和右移运算得到散列值,保证分布均匀且高效。
策略性能分布均匀性
0(随机)高优
1(指针运算)极高良

3.3 重写hashCode()时必须遵守的约定

在Java中,当重写equals()方法时,必须同时重写hashCode(),以确保对象在哈希集合(如HashMap、HashSet)中的正确行为。
核心约定
  • 同一对象多次调用hashCode()应返回相同整数,前提是影响equals()的字段未被修改;
  • 若两个对象通过equals()比较相等,则它们的hashCode()必须返回相同值;
  • 若两个对象不相等,hashCode()可返回不同或相同的值,但尽量返回不同值以提升性能。
示例代码
public class Person {
    private String name;
    private int age;

    @Override
    public int hashCode() {
        int result = 17;
        result = 31 * result + name.hashCode();
        result = 31 * result + age;
        return result;
    }
}
该实现使用质数31作为乘数,能有效减少哈希冲突。每次计算基于与equals()相关的字段,确保相等对象拥有相同哈希码。

第四章:典型去重失败场景与解决方案

4.1 未重写hashCode()和equals()导致的问题

在Java中,当自定义对象作为HashMap或HashSet的键或元素时,若未重写equals()和hashCode()方法,将沿用Object类的默认实现,可能导致逻辑错误。
问题表现
两个内容相同的对象可能被视为不同键,破坏集合的唯一性与查找效率。

class Person {
    String name;
    int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}
// 使用Person作为HashMap的key
Map<Person, String> map = new HashMap<>();
map.put(new Person("Alice", 25), "value1");
map.put(new Person("Alice", 25), "value2");
System.out.println(map.size()); // 输出2,而非预期的1
上述代码中,两个Person对象内容相同,但因未重写hashCode(),哈希码不同,导致被存入不同桶位;同时equals()未重写,无法判断逻辑相等。
核心规范
根据Java规范,若重写equals(),必须重写hashCode(),确保相等对象拥有相同的哈希值。

4.2 只重写其中一个方法引发的陷阱

在面向对象编程中,equals() 和 hashCode() 方法通常成对出现。若只重写其中一个,可能破坏集合类(如 HashMap)的正常行为。
常见错误示例
public class User {
    private String id;
    
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof User)) return false;
        User user = (User) o;
        return id.equals(user.id);
    }
    // 未重写 hashCode()
}
上述代码中仅重写了 equals(),但未重写 hashCode(),导致两个逻辑相等的对象可能产生不同的哈希值。
后果分析
  • 在 HashMap 中,相同 equals() 结果的对象必须具有相同 hashCode()
  • 否则对象无法被正确检索,出现“存入后找不到”的现象
正确做法是同时重写两个方法,确保一致性。

4.3 可变字段参与哈希计算的风险

当对象的可变字段参与哈希值计算时,若字段在对象生命周期内发生修改,会导致哈希码不一致,进而破坏基于哈希的数据结构(如 HashMap、HashSet)的契约。
典型问题场景
以下 Java 示例展示了可变字段引发的问题:

public class MutableKey {
    private String name;
    
    public MutableKey(String name) { this.name = name; }
    
    @Override
    public int hashCode() { return name.hashCode(); }
    
    // 可变 setter 方法
    public void setName(String name) { this.name = name; }
}
若该对象作为 HashMap 的 key,调用 setName() 后,其哈希码改变,导致无法通过原引用定位到对应桶位置,造成数据丢失或查找失败。
规避策略
  • 使用不可变对象作为哈希计算依据
  • 在构造时冻结关键字段,避免运行时修改
  • 重写 hashCode() 时仅依赖不可变属性

4.4 实战案例:自定义对象去重修复全过程

在某次数据迁移任务中,发现用户自定义对象因缺少唯一标识导致重复插入。问题根源在于未覆盖 `equals()` 与 `hashCode()` 方法,致使集合无法识别逻辑相同对象。
核心修复代码

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (!(o instanceof UserDTO)) return false;
    UserDTO user = (UserDTO) o;
    return Objects.equals(id, user.id) && 
           Objects.equals(email, user.email);
}

@Override
public int hashCode() {
    return Objects.hash(id, email);
}
上述实现确保两个对象在 ID 与邮箱均相同时被视为同一实体。`Objects.hash()` 提供稳定哈希值,避免 `HashSet` 出现冲突。
验证流程
  • 构造包含重复数据的测试集
  • 使用 `Stream.distinct()` 去重并比对前后数量
  • 通过单元测试验证逻辑一致性

第五章:深入理解Java集合设计哲学

接口抽象与实现分离
Java集合框架通过接口与实现的分离,实现了高度的灵活性。例如,List 接口可由 ArrayList、LinkedList 等不同类实现,适应不同场景。
  • ArrayList 基于动态数组,适合随机访问
  • LinkedList 基于双向链表,插入删除效率更高
  • 开发中应优先使用接口声明变量:
    List<String> list = new ArrayList<>();
迭代器模式的统一访问
所有集合都实现了 Iterable 接口,支持统一遍历方式:
for (String item : collection) {
    System.out.println(item);
}
该设计屏蔽了底层数据结构差异,提升代码可维护性。
线程安全的设计权衡
原始集合如 HashMap 非线程安全,但提供了多种并发控制方案:
集合类型适用场景同步机制
Vector传统同步需求方法级 synchronized
Collections.synchronizedList()包装已有列表客户端加锁
ConcurrentHashMap高并发读写分段锁 + CAS
函数式编程的融合
Java 8 引入 Stream API,使集合操作更声明式:
list.stream()
    .filter(s -> s.startsWith("A"))
    .map(String::toUpperCase)
    .sorted()
    .forEach(System.out::println);
这一演进体现了从“如何做”到“做什么”的范式转变。
Java List去重性能优化:HashSet、LinkedHashSet与Stream API实战对比 在Java集合操作中,数据去重是一个基础且高频的需求,其核心原理是利用哈希表(Hash Table)或类似数据结构实现元素的唯一性判断。哈希表通过hashCode()和equals()方法快速定位元素,从而实现O(1)时间复杂度的查找,这是高效去重的技术基石。从技术价值看,合理的去重方案能有效提升程序性能、减少内存占用,并保障数据一致性。在实际应用场景中,开发者常需根据数据规模、顺序要求及运行环境进行选型。例如,对于大数据量处理,需警惕内存溢出(OutOfMemoryError)风险;而在高并发服务中,不当 阅读详情

相关推荐

2025年VSCode AI插件实战:如何用Devika+Continue+Tabby三件套10倍提升开发效率

本文详细介绍了2025年VSCode AI插件Devika、Continue和Tabby的三件套组合,如何通过智能开发工作流10倍提升开发效率。从项目架构生成到上下文感知辅助,再到本地化智能编码,这套方案实现了从需求分析到代码生成的全流程自动化,特别适合中大型项目开发。

weixin_26911099的博客 270

Set集合不重复原理

Set集合之所以不重复就是因为Set集合中覆盖重写了hashCode方法和equals方法。

weixin_52693727的博客 2542

人工智能机器学习从入门到高级学习资料(含资料下载地址)

机器学习是一个技术含量较高的领域,高效学习需要多种途径相结合.以下是一些推荐的学习资源。首先介绍几个比较有用的社区,包含了丰富的学习资料

2401_86900375的博客 1648

HashSet中为什么不允许放重复的值

<br />主要是因为hahcode()<br /> <br />Hashcode()方法的作用: 哈希算法,将集合分成若干个区域,每个对象在放入集合之前由计算<br /> <br />机计算出一个哈吸码,可以将哈希码分组,每组分别对应某个区域,根据一个对象的哈希码可以<br /> <br />确定该对象应存储在哪个区域。当再次向哈希表中存入对象的时候,依旧这样儿运算,但可以快<br /> <br />速的判断里面是否有与现在要存的对象相同的,如果有则不能对此对象进行存储<br /> <br /> <br

ET0019的专栏 6217

从拆解图看懂空心杯电机:有刷 vs 无刷内部结构全解析(附DIY注意事项)

本文深入解析有刷与无刷空心杯电机的内部结构差异,通过高清拆解图展示关键部件工艺特点,并分享实用的维护技巧和检测方法。重点对比两种电机在效率、寿命和适用场景上的优劣,为DIY爱好者提供详细的注意事项和操作指南。

xgboost6farmer的博客 518

oVirt 4.4.10超详细安装指南:从零搭建企业级虚拟化环境(附常见错误排查)

本文提供了oVirt 4.4.10企业级虚拟化平台的超详细安装指南,涵盖环境规划、系统准备、Engine安装配置、计算节点部署、存储系统集成及高级运维技巧。通过实战操作手册和常见错误排查方法,帮助用户从零搭建稳定高效的虚拟化环境,特别适合企业IT管理员参考实施。

wasm7browser的博客 351

HashSet为什么元素不重复

打开HashSet源码,发现其内部维护了一个HashMap: public class HashSet extends AbstractSet implements Set, Cloneable, java.io.Serializable { static final long serialVersionUID = -5024744406713321676L; private transient ...

qq_34118946的博客 1425

FortiOS 存在身份验证绕过导致命令执行漏洞(CVE-2024-55591)

FortiOS 是 Fortinet 公司开发的操作系统,作为 Fortinet 安全平台的核心,提供全面的网络安全功能。 它将网络和安全功能无缝集成,支持跨本地、云、混合和融合 IT/OT/IoT 基础设施环境的统一管理。 FortiOS 7.6 版本引入了生成式人工智能助手、数据保护、托管服务和单一代理等新功能,进一步增强了其安全性和性能。

缘梦未来的博客 1841

HashSet 是如何保证元素不重复的?

本文已收录Git仓库,开源地址:gitee.com/mydb/interv… HashSet 实现了 Set 接口,由哈希表(实际是 HashMap)提供支持。HashSet 不保证集合的迭代顺序,但允许插入 null 值。也就是说 HashSet 不能保证元素插入顺序和迭代顺序相同。 HashSet 具备去重的特性,也就是说它可以将集合中的重复元素自动过滤掉,保证存储在 HashSet 中的元素都是唯一的。 1.HashSet 基本用法 HashSet 基本操作方法有:add(添加)...

欢迎来到我的博客 4139

出现 Error occurred during initialization of VMagent library failed Agent OnLoad 解决方法

ntelliJ IDEA启动时出现"Agent library failed to load"错误,主要原因是JVM代理加载失败。解决方法包括:1)完全卸载并删除用户目录下的JetBrains配置文件;2)检查并修改idea64.exe.vmoptions文件,确保路径正确并删除不必要的-javaagent参数;

码农研究僧的博客 2484

华为od 面试八股文_测试/测试开发_01_含答案

华为od面试八股文_测试/测试开发_01_含答案

MISAYAONE的博客 3816

踩坑——ArrayList使用HashSet去重无效(已解决)

踩坑——ArrayList使用HashSet去重无效(已解决)

是阿超 1167

AgentScope实战训练营:从零搭建一个完整的A2A Agent应用

2024年4月,Google在Google Cloud Next大会上正式提出了A2A(Agent-to-Agent)协议,这是一个开放协议,旨在让不同的AI Agent之间能够像微服务一样相互发现、相互调用。通俗地讲:A2A协议就是AI Agent世界的HTTP协议——有了它,一个Agent可以把自己的能力以标准化的方式暴露出去,另一个Agent可以无缝地发现并调用它。本文将基于阿里巴巴开源的(Apache 2.0协议),手把手带你从零搭建一个完整的A2A Agent应用。

program哲学 565

Java 【数据结构】 哈希(Hash超详解)HashSet&HashMap【神装】

哈希桶机制通过将冲突的元素组织在一起,而非直接覆盖,保证了哈希表的灵活性和高效性。它允许哈希表在面对大量数据时仍能保持较好的性能,尤其是在冲突较多的情况下。通过调整哈希函数、负载因子和适时的扩容,可以进一步优化哈希表的效率。在Java中,HashMap和HashSet就是使用哈希桶来实现的,它们是Java集合框架中非常重要的组件。Java中的HashSet是一个实现了Set接口的集合类,它提供了一种存储不可重复元素的高效数据结构。

2302_79806056的博客 2万+

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

STM32F407中文手册

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

Set集合的特点,HashSet去重的几个重要问题

HashSet去重原理

小助手爱编程 440

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

对于hash系列 hashset,hashtable,hashMap的的去重

了解哈希 哈希概念 把任意长度的输入(又叫做预映射pre-image)通过散列算法变换成固定长度的输出,该输出就是散列值。 哈希存储中的碰撞 对不同的关键字可能得到同一哈希值,即key1≠key2,而f(key1)=f(key2),这种现象称碰撞 哈希值 是jdk根据对象的内存地址或字符串或数字通过哈希函数计算出来的int类型的数值。 ...

qq_39497607的博客 1041

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

【Java每日一练-Day9】HashSet底层实现?如何保证元素不重复?与HashMap的关联一次说透!

若key已存在(哈希值相同 + equals方法返回true):HashMap的put方法会返回旧的value(即PRESENT),HashSet会认为元素已存在,不执行添加操作;时,默认调用Object类的hashCode(),返回对象的内存地址哈希值;:HashSet不保证元素的存储顺序,也不保证顺序永久不变(如HashMap扩容时,元素的索引位置会变化,HashSet的遍历顺序也会变);若key不存在:HashMap会插入新的key-value对,HashSet会认为元素添加成功,返回true。

Xiong_Ji537的博客 1309

Hash表与Hashset

HashSet 是 Set 接口的典型实现,大多数时候使用 Set 集合时都使用这个实现类。 HashSet 按 Hash 算法来存储集合中的元素,因此具有很好的存取、查找、删除 性能。 HashSet 具有以下特点: 不能保证元素的排列顺序 HashSet 不是线程安全的 集合元素可以是 null HashSet 集合判断两个元素相等的标准:两个对象通过 hashCode() 方法比较相 等,并且两个对象的 equals() 方法返回值也相等。 对于存放在Set容器中的对象,对应的类一定要重写equa

qq_56457318的博客 1407

揭秘HashSet如何实现高效去重:从hashCode到equals的底层逻辑解析

掌握Java集合HashSet去重原理,深入解析hashCode与equals协同工作机制,揭示对象唯一性判定底层逻辑。适用于集合去重、性能优化等场景,理解哈希表存储机制与冲突处理策略,提升代码效率,值得收藏。

IterStream的博客 315

HashSet集合去重机制全曝光(add方法返回boolean值的真正含义)

掌握HashSet集合去重原理,深入解析HashSet add 方法的返回值意义。通过add方法返回boolean值判断元素是否添加成功,揭示其底层哈希机制与去重逻辑,适用于集合操作去重场景,提升代码效率,值得收藏。

codeink的博客 289

Java List去重性能优化:从HashSet到Stream API的实战对比

在数据处理中,集合去重是常见的基础操作,其核心原理是利用数据结构的唯一性特性来消除重复元素。哈希表(HashSet)通过O(1)的平均时间复杂度实现高效去重,是性能最优的底层技术方案。Java 8引入的Stream API则提供了声明式的函数式编程范式,其distinct()操作在简化代码的同时,内部也基于集合实现去重。这些技术在处理数据库查询结果、日志分析或接口数据整合等场景中具有重要价值,能有效提升应用性能与代码可读性。本文聚焦于Java中List去重的多种实现方案,通过对比HashSet、Linked

cuanji3287的博客 547

关于HashSet的五个问题

当元素插入到哈希表中时,通过哈希函数计算得到元素的哈希码,并据此确定元素应该存储在数组的哪个槽位上。哈希函数将元素的键(或值)映射到数组的索引位置上,理想情况下,不同的元素应该被映射到不同的数组位置上,从而实现均匀的分布。当你遍历 HashSet 中的元素时,元素的顺序看起来是随机的,这是因为它们在哈希表中的存储位置是根据哈希码计算得到的,并不代表它们被插入集合的顺序。HashSet 添加元素的过程涉及哈希码的计算、数组的索引定位、哈希冲突的解决以及重复元素的检查,这些步骤保证了元素的唯一性和高效的存储。

weixin_53891720的博客 1327

哈希表,HashMap与HashSet

1. **数据结构**:HashMap 是基于哈希表的 Map 接口实现,以键值对(key-value)的形式存储数据。在 JDK 1.8 之前,HashMap 由数组+链表组成,而在 JDK 1.8 之后,当链表长度大于阈值(默认为 8)且数组长度大于 64 时,链表会转换为红黑树,以提高查询效率。2. **哈希函数**:HashMap 使用哈希函数将键映射到数组的索引位置。通过取键的 hashCode 值、进行高位运算和取模运算等步骤,得到最终的索引值。这样可以在数组中快速定位键值对的存储位置。

vbgesab的博客 710

HashSet 中的哈希值计算

HashSet中每个对象的哈希值是通过调用hashCode()方法计算得到的,而hashCode()方法的实现应当与equals()方法保持一致,这样才能保证HashSet的正确性和高效性。

m0_50742275的博客 471

为什么要重写hashCode和equals方法

文章目录前言一、什么是hashCode?二、向HashSet添加数据流程三、不重写hashCode但重写了equals怎么样四、重写了hashCode和equals比较逻辑总结 前言 在idea编译器中重写equals方法和重写hashCode方法捆绑在一起,同时在学习到set集合时也常看到各种资料写着hashCode和equals方法都需要重写,这是为什么呢? 以下是我的个人理解 一、什么是hashCode? hashCode是Object类中定义的一个方法,则任何类都继承自Object方法,常见的

weixin_43411127的博客 1941

Set\HashSet集合为什么能去重(转)

如果想查找一个集合中是否包含有某个对象,大概的程序代码怎样写呢?当发现某个元素与要查找的对对象进行equals方法比较的结果相等时,则停止继续查找并返回肯定的信息,否则返回否定的信息。如果是一个集合中有很多元素,譬如有一万个元素,并且没有包含要查找的对象时,则意味着你的程序需要从该集合中取出一万个元素进行啄一的比较才能得到结论,有人发明了一种hashCode算法,来提高查找的效率,这种方...

dawei5565的博客 294
上一篇: MyBatis批量插入如何提速10倍?:深入解析VALUES多值SQL的最佳实践
下一篇: NullPointerException调试噩梦终结?Java 14带来5大关键改进,你不可不知
InstrFun
博客等级 码龄1年 142粉丝 1990原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值