HashSet源码解析(基于Java8)

简介: List保证元素的添加顺序,元素可重复Set不保证元素的添加顺序,元素不可重复public class Test { public static void main(String[] arg...
  • List保证元素的添加顺序,元素可重复
  • Set不保证元素的添加顺序,元素不可重复


    img_8b451059c0ab1b6c88fef68ce2cbc8b2.png

    img_2368fcce0bac476aa9357d0f297ce120.png
img_6047ebdca4f32163a6edd6f3d550ab37.png
public class Test {
    public static void main(String[] args){
        Set<String> strSet = new HashSet<>();//new了一个HashSet
        strSet.add("张三");
        strSet.add("李四");
        strSet.add("王五");
        strSet.add("赵六");

        System.out.println("strSet : " + strSet);
        System.out.println("strSet.size() : " + strSet.size());
        System.out.println("strSet里是否为空 : " + strSet.isEmpty());

        System.out.println("删除王五。。。。");
        boolean delFlag = strSet.remove("王五");
        System.out.println("删除王五是否成功" + delFlag);
        System.out.println("删除王五后的strSet : " + strSet);
        System.out.println("strSet中是否包含王五:" + strSet.contains("王五"));
        System.out.println("strSet中是否包含张三:" + strSet.contains("张三"));

        System.out.println("clear清除元素...");
        strSet.clear();
        System.out.println("clear清除元素后的strSet : " + strSet);
        System.out.println("strSet长度 : " + strSet.size());
        System.out.println("strSet里是否为空 : " + strSet.isEmpty());

    }
}

new一个HashSet,只要是看到new,肯定在堆内存里开辟了一块空间,先找到HashSet的构造函数


img_1b418607eb3384461ddedadb28c22c6e.png

出现了HashMap,再看一下map


img_d97f70f67de1db4392ca87c3835188f3.png

继续执行以下代码,往strSet添加元素"张三"
strSet.add("张三");   

再看

add

img_b61fcbdab882d21cb2bf0dd066a5541b.png

就是调用底层HashMap的put方法,把"张三"作为key, PRESENT作为value放在HashMap
HashMap如果 putkey重了,会返回被覆盖的 value(oldValue),否则返回 null
HashSet又包装了,如果 key没有重( oldValue == null),就返回 true,否则返回 false
继续看这个 PRESENT
img_891f233b85b03e97d25f6b7667230496.png

很简单就是new了一个Object,所有元素的value都指向Object对象
HashSet虽然底层是用HashMap来实现的,但由于用不到HashMap的value,所以不会为底层HashMap的每个value分配一个内存空间,因此并不会过多的占用内存,请放心食用。

再来看看示例代码里的

size()

img_d0996e33af88c262094ce4dde07b9ba3.png

isEmpty()

img_ca6c9c43bdbc872f9a9d7057ee0ddc16.png
image.png

remove()

img_f9963b6b4513a6e71ea8a3e998f86d2c.png

contains()

img_30660ebe5efb19df2a8c0cc26606a058.png

clear()

img_fe3fdd1a625b60d9a7d4872144cc61bd.png

基本上没什么逻辑代码,就是复用了HashMap里的方法而已
HashSet就是利用HashMap来实现的。

大胆的猜测一下,TreeSet是不是也是用TreeMap来实现的呢


img_df0c934da61bb80434822d265eb8f69d.png

构造函数this调了另一个构造函数


img_2e1f12c2d5133b932b34c0ad676ba449.png

再来看m
img_54126d27a19c6f0a456781f1adac80b6.png

这个m是NavigableMap类型的,NavigableMap只是一个接口而已


img_938661bf6b57cf1a477ef685ec4d035d.png

再来看TreeMap,实现了NavigableMap这个接口
绕了好大一个圈,其实就是相当于
NavigableMap m = new TreeMap<>();

也就是说,TreeSet底层实现也是利用TreeMap来实现的,再来看看TreeSet的其它方法
TreeMapadd是调用底层TreeMapput,只是改了个名字而已
其它方法大致上也是如此,就不一一举例说明了

小结

HashSet底层声明了一个HashMap,HashSet做了一层包装,操作HashSet里的元素时其实是在操作HashMap里的元素。
TreeSet底层也是声明了一个TreeMap,操作TreeSet里的元素其实是操作TreeMap里的元素。

附 关于有序性

“不保证有序”和“保证无序”不等价,HashSet的iterator是前者而不是后者,所以在一次运行中看到有序的结果也是正常的,但不能依赖这个有序行为。况且HashSet并不关心key的“排序”,就算其iterator“有序”通常也是说“按元素插入顺序”(LinkedHashSet就支持插入顺序遍历)。
JDK8的HashSet实现变了,导致元素插入的位置发生了变化;iterator自身实现的顺序倒没变,还是按照内部插入的位置顺序来遍历,于是题主就看到了JDK7和JDK8的结果不一样。具体来说,是JDK7与JDK8的java.util.HashMap的hash算法以及HashMap的数据布局发生了变化。题主插入HashSet的是Integer,其hashCode()实现就返回int值本身。所以在对象hashCode这一步引入了巧合的“按大小排序”。然后HashMap.hash(Object)获取了对象的hashCode()之后会尝试进一步混淆。JDK8版java.util.HashMap内的hash算法比JDK7版的混淆程度低;在[0, 2^32-1]范围内经过HashMap.hash()之后还是得到自己。外加load factor正好在此例中让这个HashMap没有hash冲突,这就导致例中元素正好按大小顺序插入在HashMap的开放式哈希表里
\

目录
相关文章
|
前端开发 Java 关系型数据库
基于Java+Springboot+Vue开发的鲜花商城管理系统源码+运行
基于Java+Springboot+Vue开发的鲜花商城管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的鲜花商城管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。技术学习共同进步
830 7
|
消息中间件 算法 安全
JUC并发—1.Java集合包底层源码剖析
本文主要对JDK中的集合包源码进行了剖析。
|
人工智能 安全 Java
智慧工地源码,Java语言开发,微服务架构,支持分布式和集群部署,多端覆盖
智慧工地是“互联网+建筑工地”的创新模式,基于物联网、移动互联网、BIM、大数据、人工智能等技术,实现对施工现场人员、设备、材料、安全等环节的智能化管理。其解决方案涵盖数据大屏、移动APP和PC管理端,采用高性能Java微服务架构,支持分布式与集群部署,结合Redis、消息队列等技术确保系统稳定高效。通过大数据驱动决策、物联网实时监测预警及AI智能视频监控,消除数据孤岛,提升项目可控性与安全性。智慧工地提供专家级远程管理服务,助力施工质量和安全管理升级,同时依托可扩展平台、多端应用和丰富设备接口,满足多样化需求,推动建筑行业数字化转型。
443 5
|
Java 开发者
重学Java基础篇—Java类加载顺序深度解析
本文全面解析Java类的生命周期与加载顺序,涵盖从加载到卸载的七个阶段,并深入探讨初始化阶段的执行规则。通过单类、继承体系的实例分析,明确静态与实例初始化的顺序。同时,列举六种触发初始化的场景及特殊场景处理(如接口初始化)。提供类加载完整流程图与记忆口诀,助于理解复杂初始化逻辑。此外,针对空指针异常等问题提出排查方案,并给出最佳实践建议,帮助开发者优化程序设计、定位BUG及理解框架机制。最后扩展讲解类加载器层次与双亲委派机制,为深入研究奠定基础。
543 0
|
存储 Java
【源码】【Java并发】【ThreadLocal】适合中学者体质的ThreadLocal源码阅读
前言 下面,跟上主播的节奏,马上开始ThreadLocal源码的阅读( ̄▽ ̄)" 内部结构 如下图所示,我们可以知道,每个线程,都有自己的threadLocals字段,指向ThreadLocalMap
659 81
【源码】【Java并发】【ThreadLocal】适合中学者体质的ThreadLocal源码阅读
|
9月前
|
存储 小程序 Java
热门小程序源码合集:微信抖音小程序源码支持PHP/Java/uni-app完整项目实践指南
小程序已成为企业获客与开发者创业的重要载体。本文详解PHP、Java、uni-app三大技术栈在电商、工具、服务类小程序中的源码应用,提供从开发到部署的全流程指南,并分享选型避坑与商业化落地策略,助力开发者高效构建稳定可扩展项目。
|
前端开发 Java 物联网
智慧班牌源码,采用Java + Spring Boot后端框架,搭配Vue2前端技术,支持SaaS云部署
智慧班牌系统是一款基于信息化与物联网技术的校园管理工具,集成电子屏显示、人脸识别及数据交互功能,实现班级信息展示、智能考勤与家校互通。系统采用Java + Spring Boot后端框架,搭配Vue2前端技术,支持SaaS云部署与私有化定制。核心功能涵盖信息发布、考勤管理、教务处理及数据分析,助力校园文化建设与教学优化。其综合性和可扩展性有效打破数据孤岛,提升交互体验并降低管理成本,适用于日常教学、考试管理和应急场景,为智慧校园建设提供全面解决方案。
734 70
|
JavaScript Java 关系型数据库
家政系统源码,java版本
这是一款基于SpringBoot后端框架、MySQL数据库及Uniapp移动端开发的家政预约上门服务系统。
427 6
家政系统源码,java版本
|
Java
【源码】【Java并发】【ReentrantLock】适合中学者体质的ReentrantLock源码阅读
因为本文说的是ReentrantLock源码,因此会默认,大家对AQS有基本的了解(比如同步队列、条件队列大概> 长啥样?)。 不懂AQS的小朋友们,你们好呀!也欢迎先看看这篇
288 13
【源码】【Java并发】【ReentrantLock】适合中学者体质的ReentrantLock源码阅读
|
供应链 JavaScript 前端开发
Java基于SaaS模式多租户ERP系统源码
ERP,全称 Enterprise Resource Planning 即企业资源计划。是一种集成化的管理软件系统,它通过信息技术手段,将企业的各个业务流程和资源管理进行整合,以提高企业的运营效率和管理水平,它是一种先进的企业管理理念和信息化管理系统。 适用于小微企业的 SaaS模式多租户ERP管理系统, 采用最新的技术栈开发, 让企业简单上云。专注于小微企业的应用需求,如企业基本的进销存、询价,报价, 采购、销售、MRP生产制造、品质管理、仓库库存管理、财务应收付款, OA办公单据、CRM等。
924 23

推荐镜像

更多
  • DNS