Java集合类HashSet实现细节

【Java集合框架】13——HashSet 类 HashSet 阅读详情

定义 

HashSet继承AbstractSet类,实现Set、Cloneable、Serializable接口。其中AbstractSet提供Set接口的骨干实现,从而最大限度地减少了实现此接口所需的工作。Set接口是一种不包括重复元素的Collection.它不保证set的迭代顺序;特别是它不保证该顺序恒久不变。此类允许使用null 元素。

对于 HashSet 而言,它是基于 HashMap 实现的,HashSet 底层采用 HashMap 来保存所有元素,因此HashSet 的实现其实非常简单,它只是封装了一个 HashMap 对象来存储所有的集合元素,所有放入 HashSet 中的集合元素实际上由 HashMap 的 key 来保存,而 HashMap 的 value 则存储了一个 PRESENT,它是一个静态的 Object 对象。

HashSet 的绝大部分方法都是通过调用 HashMap 的方法来实现的,因此 HashSet 和 HashMap 两个集合在实现本质上是相同的。

  1. class Name  
  2. {  
  3.     private String first;   
  4.     private String last;   
  5.       
  6.     public Name(String first, String last)   
  7.     {   
  8.         this.first = first;   
  9.         this.last = last;   
  10.     }   
  11.   
  12.     public boolean equals(Object o)   
  13.     {   
  14.         if (this == o)   
  15.         {   
  16.             return true;   
  17.         }   
  18.           
  19.     if (o.getClass() == Name.class)   
  20.         {   
  21.             Name n = (Name)o;   
  22.             return n.first.equals(first)   
  23.                 && n.last.equals(last);   
  24.         }   
  25.         return false;   
  26.     }   
  27. }  
  28.   
  29. public class HashSetTest  
  30. {  
  31.     public static void main(String[] args)  
  32.     {   
  33.         Set<Name> s = new HashSet<Name>();  
  34.         s.add(new Name("abc", "123"));  
  35.         System.out.println(  
  36.         s.contains(new Name("abc", "123")));  
  37.     }  
  38. }   
上面程序中向 HashSet 里添加了一个 new Name("abc", "123") 对象之后,立即通过程序判断该 HashSet 是否包含一个 new Name("abc", "123") 对象。粗看上去,很容易以为该程序会输出 true。 

实际运行上面程序将看到程序输出 false,这是因为 HashSet 判断两个对象相等的标准除了要求通过 equals() 方法比较返回 true 之外,还要求两个对象的 hashCode() 返回值相等。而上面程序没有重写 Name 类的 hashCode() 方法,两个 Name 对象的 hashCode() 返回值并不相同,因此 HashSet 会把它们当成 2 个对象处理,因此程序返回 false。 

细节剖析

1.为什么要重写equals方法和hashCode方法(技术实现原理):

程序向HashSet中添加一个对象时,先用hashCode方法计算出该对象的哈希码。

比较:

        (1),如果该对象哈希码与集合已存在对象的哈希码不一致,则该对象没有与其他对象重复,添加到集合中!

        (2),如果存在于该对象相同的哈希码,那么通过equals方法判断两个哈希码相同的对象是否为同一对象(判断的标准是:属性是否相同)

                1>,相同对象,不添加。

                2>,不同对象,添加!


此时会产生如下疑问:

1,为什么哈希码相同了还有可能是不同对象?

2,为什么经过比较哈希码还需要借助equals方法判断?

首先:

按照Object类的hashCode方法,是不可能返回两个相同的哈希码的。(哈希码唯一标志了对象

)

 然后:

Object类的hashCode方法返回的哈希码具有唯一性(地址唯一性),但是这样不能让程序的运行逻辑符合现实生活。(这个逻辑就是:属性相同的对象被看作同一个对象。)为了让程序的运行逻辑符合现实生活,Object的子类重写了hashCode的方法(基本数据类型的实现类都已经重写了两个方法,自定义的类要软件工程师自己重写)

重写的宗旨是什么?

重写就是为了实现这样的目的:属性相同的不同对象在调用其hashCode方法后,返回的是同样的哈希码。

但是

我们在重写的时候,发现几乎所有的写法都无法避免一个bug:有一些属性不同的对象(当然是不同的对象),会返回相同的哈希码。(即 重码)

最后:

为了解决这个问题:在哈希码相同的时候,再用equals方法比较两个对象的对应属性是否相同,这样,确保了万无一失。

这样:上面两个问题得到解决。


重写hashcode()和equals()方法后的代码

  1. class Name   
  2. {   
  3.     private String first;  
  4.     private String last;  
  5.     public Name(String first, String last)  
  6.     {   
  7.         this.first = first;   
  8.         this.last = last;   
  9.     }   
  10.     // 根据 first 判断两个 Name 是否相等  
  11.     public boolean equals(Object o)   
  12.     {   
  13.         if (this == o)   
  14.         {   
  15.             return true;   
  16.         }   
  17.         if (o.getClass() == Name.class)   
  18.         {   
  19.             Name n = (Name)o;  
  20.             // 使用String类中已经重写的equals()方法 
  21.             return n.first.equals(first);   
  22.         }   
  23.         return false;   
  24.     }   
  25.        
  26.     // 根据 first 计算 Name 对象的 hashCode() 返回值  
  27.     public int hashCode()   
  28.     {   
  29.         // 使用String类中已经重写的hashcode()方法
  30.         return first.hashCode();   
  31.     }  
  32.   
  33.     public String toString()   
  34.     {   
  35.         return "Name[first=" + first + ", last=" + last + "]";   
  36.     }   
  37.  }   
  38.    
  39.  public class HashSetTest2   
  40.  {   
  41.     public static void main(String[] args)   
  42.     {   
  43.         HashSet<Name> set = new HashSet<Name>();   
  44.         set.add(new Name("abc" , "123"));   
  45.         set.add(new Name("abc" , "456"));   
  46.         System.out.println(set);   
  47.     }   
  48. }  



【算法学习】字符串Hash入门 字符串Hash入门 Hash方法 自然溢出方法 Hash公式 单Hash方法 Hash公式 举例 双Hash方法 Hash公式 获取子串的Hash 例子 公式 字符串Hash的应用 字符串Hash入门 字符串Hash可以通俗的理解为,把一个字符串转换为一个整数。 如果我们通过某种方法,将字符串转换为一个整数,就可以便的确定某个字符串是否重复出现过,这是最简单... 阅读详情

相关推荐

python123题目——个税计算器

类型:简单分支。

m0_62488776的博客 5802

Java中哈希集(HashSet)概念,实现以及操作

Java中哈希集(HashSet)概念,实现以及操作

Sueko的博客 4万+

【电弧故障检测算法全解析,电弧串扰问题分析和解决算法】

本文系统分析了电弧故障检测算法及串扰问题解决方案。电弧检测主要采用时频域分析和机器学习方法,通过提取高频噪声、波形畸变等特征实现故障识别。针对电弧串扰问题,提出了自适应滤波、盲源分离和时频联合分析等算法。研究给出了Python和C语言的算法实现示例,包括高频能量检测、过零率计算和陷波滤波器设计。最后指出算法优化方向:实时性提升可采用滑动窗口FFT和硬件加速;抗干扰增强需结合硬件滤波;机器学习扩展可引入随机森林等分类器。该研究为电弧故障检测系统开发提供了完整的技术路线。

syttt的专栏 891

JAVA知识点 HashSet 集合的用法[案例+代码+总结]

JAVA知识点 HashSet 集合的用法[案例+代码+总结] 主要说明HashSet 集合的特点。将Object类存入HashSet的方法。

心态的博客 4109

单目视觉定位:深入解析PNP算法在机器人导航中的实战应用

本文深入解析了PNP算法在机器人单目视觉定位中的核心原理与实战应用。通过拆解坐标变换四步,详细阐述了如何从二维图像点反求相机三维位姿。文章结合OpenCV的solvePnP函数,提供了算法选择、参数调优及结果后处理的实用指南,并针对机器人导航中的特征匹配、尺度不确定性等挑战,给出了鲁棒性优化与实时性平衡的解决方案。

weixin_29083649的博客 419

避坑指南:CesiumLab+ENVI处理Sentinel-2影像数据的完整流程

本文提供了一份详细的避坑指南,完整介绍了如何利用CesiumLab和ENVI工具链,将Sentinel-2卫星影像处理成可供Cesium三维地球引擎加载的离线瓦片数据。内容涵盖数据获取、SNAP预处理、ENVI影像增强合成以及CesiumLab切片配置等全流程实战步骤与关键参数优化,旨在帮助工程师高效构建自主可控的高精度离线地图服务。

weixin_29248653的博客 288

Java中的集合类:HashSet

Java中的集合类 1、HashSet 1.1、HashSet的简介 1.2、HashSet的底层实现原理 1.3、HashSet的操作方法 1.3.1、构造方法 1.3.2、add方法 1.3.3、iterator方法 1.3.4、size方法 1.3.5、contains方法 1.3.6、remove方法 1.3.7、clear方法 1.3.8、isEmpty方法

friend_X的博客 815

基于A*算法的二维栅格地图路径规划与避障MATLAB仿真

本文将介绍如何使用MATLAB编写基于A*算法的二维栅格地图路径规划与避障的仿真程序。我们可以使用二维数组表示地图,其中每个元素表示一个栅格的状态,例如1表示障碍物,0表示可行走区域。接下来,我们需要定义A*算法的节点类。G值表示从起始节点到当前节点的代价,H值是启发式函数估计的从当前节点到目标节点的代价。算法,我们可以有效地找到起始点到目标点的最短路径,并在仿真中进行可视化展示。算法的基本思路是从起始节点开始,按照一定的启发式函数选择下一个节点,直到找到目标节点或者遍历完所有可行走区域。

ByteWhizX的博客 1273

Java集合详解8:Java集合类细节精讲

今天我们来探索一下Java集合类中的一些技术细节。主要是对一些比较容易被遗漏和误解的知识点做一些讲解和补充。可能不全面,还请谅解。 本文参考:cmsblogs.com/?cat=5 具体代码在我的GitHub中可以找到 github.com/h2pl/MyTech 文章首发于我的个人博客: h2pl.github.io/2018/05/13/… 更多关于Java后端学习的内容请到我的优快云博客上...

weixin_33781606的博客 208

泛微OA集成阿里云短信(E9保姆教程)

泛微OA集成阿里云短信(E9保姆教程)

技术分享 515

IEEE69节点数据(Matlab)

IEEE69节点数据(Matlab)

weixin_46039719的博客 1160

java arraylist 初始化_Java集合详解8:Java集合类细节精讲

今天我们来探索一下Java集合类中的一些技术细节。主要是对一些比较容易被遗漏和误解的知识点做一些讲解和补充。可能不全面,还请谅解。本文参考:http://cmsblogs.com/?cat=5初始容量集合是我们在Java编程中使用非常广泛的,它就像大海,海纳百川,像万能容器,盛装万物,而且这个大海,万能容器还可以无限变大(如果条件允许)。当这个海、容器的量变得非常大的时候,它的初始容量就会显得很重...

weixin_39712821的博客 345

124、LLC谐振变换器的矩阵变压器设计

摘要 本文分享了LLC谐振变换器中矩阵变压器的实战设计经验。针对大功率LLC单颗变压器的痛点(绕组层数多、散热不均、漏感一致性差),作者提出将大变压器拆分为多个小变压器单元(建议6个),通过原边串联、副边并联的方式实现功率分配。详细解析了磁芯选型、匝比计算、绕组结构、漏感控制和散热设计等关键参数,特别强调了小磁芯优势、等效匝比计算误区以及三明治绕法的重要性。文中还总结了调试过程中的谐振频率偏移和均流问题解决方案,并给出了矩阵数量选择、磁芯材质、绝缘材料等实用建议。作者指出,矩阵变压器在2kW以上LLC应用中

Jack010169的博客 168

JAVA进阶之集合类(一)

JAVA进阶之集合类(一) 一、数组与集合类的关系    我们知道数组可以用来保存多个数据或者对象,但是使用数组却存在两个问题:数组大小不可扩展数组无法反映映射关系    举例来说,我们创建一个数组,int[] a = new int[3],用数组a来保存我们的数组。在创建的时候,我们就需要声明数组的大小,这样虚拟机才会分配一个连续的内存空间来存储数组。假如此时我又有了新的数据,但是由于我们的数组...

大喵爱吃鱼的博客 394

IMSL CNL 7.0.0 (x86-64)Crack

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

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

hashset实现原理_Java集合详解7:HashSet,TreeSet与LinkedHashSet

今天我们来探索一下HashSet,TreeSet与LinkedHashSet的基本原理与源码实现,由于这三个set都是基于之前文章的三个map进行实现的,所以推荐大家先看一下前面有关map的文章,结合使用味道更佳。具体代码在我的GitHub中可以找到https://github.com/h2pl/MyTech文章首发于我的个人博客:https://h2pl.github.io/2018/05/12...

weixin_39702400的博客 105

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

Java常见集合类

这段代码展示了如何创建 `ArrayList`、`HashSet`、`HashMap` 和 `PriorityQueue` 并向其中添加数据。- 主要实现类有 `HashMap`, `TreeMap`, `LinkedHashMap` 和 `Hashtable`。- 主要实现类有 `LinkedList`(也可以作为队列使用), `PriorityQueue`。- 主要实现类有 `HashSet`, `TreeSet` 和 `LinkedHashSet`。

2401_86504718的博客 286

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

Java集合类: Set、List、Map、Queue使用场景梳理

转载来源:http://www.cnblogs.com/LittleHann/p/3690187.html 本文主要关注Java编程中涉及到的各种集合类,以及它们的使用场景 相关学习资料 http://files.cnblogs.com/LittleHann/java%E9%9B%86%E5%90%88%E6%8E%92%E5%BA%8F%E5%8F%8Ajava%E9%9B%86%E5%...

qq_35939148的博客 335

ArrayList和HashSet的Contains()方法

首先来看一道笔试题: import java.util.ArrayList; import java.util.HashSet; public class Foo { int value; Foo(int value) {

fwwdn's tech blog 6430

Java集合类

Java集合类1.特点1.1 Collection每个“槽”中只能保存一个元素1.1.1 Set 相同数只保存一次 除TreeSet外,所有Set均与Collection完全一样 1.1.2 List 以特定顺序保存数据 尽管List要用的方法都在Collection中,但它与Collection存在着明显不同 1.1.3 Queue 不用Collectioin方法 1.2 Map每个“槽”中能保存

编码人生 229

第三章:java基本功之常用java集合实现细节

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_33676492的博客 94

java集合类

Collection package collectionTest; // import java.util.ArrayList; import java.util.Iterator ; import java.util.Collection; // // // import student.Student; // public class collectionTest01 { public...

xoxcu的博客 217

面试官:HashSet 的实现原理是怎样的?底层是什么数据结构?被问到了。。

HashSet是Java集合Set的一个实现类,Set是一个接口,其实现类除HashSet之外,还有TreeSet,并继承了Collection,HashSet集合很常用,同时也是程序员面试时经常会被问到的知识点,下面是结构图{}

m0_73311735的博客 251

Java 集合面试题真实场景还原

Arrays.asList转换list之后,如果修改了数组的内容,list会受影响,因为它的底层使用的Arrays类中的一个内部类ArrayList来构造的集合,在这个集合的构造器中,把我们传入的这个集合进行了包装而已,最终指向的都是同一个内存地址。list用了toArray转数组后,如果修改了list内容,数组不会影响,当调用了toArray以后,在底层是它是进行了数组的拷贝,跟原来的元素就没啥关系了,所以即使list修改了以后,数组也不受影响。比如原来的顺序是AB,扩容后的顺序是BA,线程二执行结束。

Go_ahead_forever的博客 1358
上一篇: Java集合类Hashtable实现细节
下一篇: java集合类TreeMap细节解析及红黑树原理
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值