在看HashSet源码的时候,意外发现底层HashMap保存的value居然不是null,而是保存一个Object作为Value。顿觉有悖常理,于是来分析一下:

HashSet的add方法:

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

可以看到这里调用底层HashMap的时候,往value里放了一个PRESENT,中文直译为“存在”,为什么叫PRESENT,很形象,待会解释。

我们再来看看PRESENT是什么:

private static final Object PRESENT = new Object();

PRESENT是一个类静态变量,也就是说整个类所有的value也就这么一个对象,而且这个对象根本没有任何意义。

带着问题去分析:

  • 问题一:按理说,HashSet只需要判断是否重复(存在),压根就不需要存放value的呀,那么存放一个null不就好了?何必存一个没有意义的Object?这个问题需要解释问题二
  • 问题二:为什么add方法需要返回值?返回值的意义是什么?
  • 问题三:如果给value存null会发生什么?

先分析问题三,如果存了一个null,我们知道HashMap是允许null值的,那么我们去看看map.put方法,存null会怎么样:

public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
/**
* Implements Map.put and related methods.
* @return previous value, or null if none
*/

看注释最后一行:返回这个key之前的value,如果这个key之前没有value,那么返回null。

如果我们HashSet存null进去,那么分析一下返回值:

  • 如果HashSet中已有了这个key,比如Set中已经有了一个KV:("张三", null),又填进去一个KV:("张三", null),此时应当返回privous value,也就是null
  • 如果HashSet中没有这个key,比如第一次添加KV:("张三", null),那么应当返回null

发现问题了,如果HashSet中把null存为value,那么无论set中是否已有重复,add方法都会返回null,那么add方法就无法检验是否重复

问题二也顺带解决了,add方法返回值,就是判断HashMap.put方法返回是否为null,也就是判断add方法添加的新元素是否已经重复

问题一也解决了,这个Object本身确实没有意义,但是它对我们Set有意义:

它唯一的意义就是,它不等于null呀。。。也就是说,只要你开心,你往里放个什么东西都行。(毕竟还是要考虑内存占用的)

现在你肯定知道为什么这个Object叫“存在”了吧?因为张麻子说过,你和钱对我都不重要,有你,对我很重要。

HashSet底层HashMap源码分析的更多相关文章

  1. jdk7 HashSet和HashMap源码分析

    先来看看HashMap的一些成员变量以及他们的含义 /** * The default initial capacity - MUST be a power of two. */ static fin ...

  2. Java HashMap源码分析(含散列表、红黑树、扰动函数等重点问题分析)

    写在最前面 这个项目是从20年末就立好的 flag,经过几年的学习,回过头再去看很多知识点又有新的理解.所以趁着找实习的准备,结合以前的学习储备,创建一个主要针对应届生和初学者的 Java 开源知识项 ...

  3. Java中HashMap源码分析

    一.HashMap概述 HashMap基于哈希表的Map接口的实现.此实现提供所有可选的映射操作,并允许使用null值和null键.(除了不同步和允许使用null之外,HashMap类与Hashtab ...

  4. HashMap源码分析和应用实例的介绍

    1.HashMap介绍 HashMap 是一个散列表,它存储的内容是键值对(key-value)映射.HashMap 继承于AbstractMap,实现了Map.Cloneable.java.io.S ...

  5. Java HashSet和HashMap源码剖析

    转自: Java HashSet和HashMap源码剖析 总体介绍 之所以把HashSet和HashMap放在一起讲解,是因为二者在Java里有着相同的实现,前者仅仅是对后者做了一层包装,也就是说Ha ...

  6. Java源码解析——集合框架(五)——HashMap源码分析

    HashMap源码分析 HashMap的底层实现是面试中问到最多的,其原理也更加复杂,涉及的知识也越多,在项目中的使用也最多.因此清晰分析出其底层源码对于深刻理解其实现有重要的意义,jdk1.8之后其 ...

  7. 源码分析系列1:HashMap源码分析(基于JDK1.8)

    1.HashMap的底层实现图示 如上图所示: HashMap底层是由  数组+(链表)+(红黑树) 组成,每个存储在HashMap中的键值对都存放在一个Node节点之中,其中包含了Key-Value ...

  8. 【JAVA集合】HashMap源码分析(转载)

    原文出处:http://www.cnblogs.com/chenpi/p/5280304.html 以下内容基于jdk1.7.0_79源码: 什么是HashMap 基于哈希表的一个Map接口实现,存储 ...

  9. JDK1.8 HashMap源码分析

      一.HashMap概述 在JDK1.8之前,HashMap采用数组+链表实现,即使用链表处理冲突,同一hash值的节点都存储在一个链表里.但是当位于一个桶中的元素较多,即hash值相等的元素较多时 ...

随机推荐

  1. XCTF练习题---MISC---Get-the-key.txt

    XCTF练习题---MISC---Get-the-key.txt flag:SECCON{@]NL7n+-s75FrET]vU=7Z} 解题步骤: 1.观察题目,下载附件 2.拿到手以后直接惊呆,挺大 ...

  2. K8s 如何提供更高效稳定的编排能力?K8s Watch 实现机制浅析

    关于我们 更多关于云原生的案例和知识,可关注同名[腾讯云原生]公众号~ 福利: ①公众号后台回复[手册],可获得<腾讯云原生路线图手册>&<腾讯云原生最佳实践>~ ②公 ...

  3. VUE3 之 自定义指令的实现 - 这个系列的教程通俗易懂,适合新手

    1. 概述 老话说的好:能屈能伸的人生,才是完满而丰富的人生. 言归正传,今天我们来聊聊 VUE 中自定义指令的实现. 2. 自定义指令 2.1 文本框聚焦的实现  <body> < ...

  4. 5.文件共享总结中篇-Linux服务器文件共享

    今天我们来讨论Linux系统之间的文件共享,包含:SCP.FTP.rz / sz.wget 一.SCP 其实我在写SSH协议常见问题排错章节中已介绍其SCP用法. 现我把SCP常用语法格式,给大家说下 ...

  5. 浅析 Linux 中的零拷贝技术

    本文探讨Linux中 主要的几种零拷贝技术 以及零拷贝技术 适用的场景 .为了迅速建立起零拷贝的概念,我们拿一个常用的场景进行引入: 引文 在写一个服务端程序时(Web Server或者文件服务器), ...

  6. 新作!分布式系统韧性架构压舱石OpenChaos

    摘要:本文首先以现今分布式系统的复杂性和稳定性的需求引出混沌工程概念,并阐述了OpenChaos在传统混沌工程上的优化与创新. 背景 随着Serverless,微服务(含服务网格)与越来越多的容器化架 ...

  7. 如何在 pyqt 中解决启用 DPI 缩放后 QIcon 模糊的问题

    问题描述 如今显示器的分辨率越来越高,如果不启用 DPI 缩放,软件的字体和图标在高分屏下就会显得非常小,看得很累人.从 5.6 版本开始,Qt 便能支持 DPI 缩放功能,Qt6 开始这个功能是默认 ...

  8. 从0到1使用kubebuiler开发operator

    介绍 假设一个Nginx的QPS(服务器一秒内处理的请求数)上限为500,如果外部访问的QPS达到了600,为了保证服务质量,必须扩容一个Nginx来分摊请求. 在Kubernetes环境中,如果外部 ...

  9. Java异常处理最佳实践

    总结一些Java异常的处理原则 Java异常处理最佳实践 不要忘记关闭资源 在finally里关闭资源 public void readFile() { FileInputStream fileInp ...

  10. Java高并发-无锁

    一.无锁类的原理 1.1 CAS CAS算法的过程是这样:它包含3个参数CAS(V,E,N).V表示要更新的变量,E表示预期值,N表示新值.仅当V值等于E值时,才会将V的值设为N,如果V值和E值不同, ...