在看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. python学习-Day32

    目录 今日内容详细 软件开发架构 概念 软件开发架构的分类 C/S架构 B/S架构 两种架构的优缺点 C/S架构: B/S架构: tip 网络编程 概念 互联网 互联网协议 OSI七层协议简介 专业设 ...

  2. 老生常谈系列之Aop--Aop的经典应用之Spring的事务实现分析(三)

    老生常谈系列之Aop--Aop的经典应用之Spring的事务实现分析(三) 前言 上一篇文章老生常谈系列之Aop--Aop的经典应用之Spring的事务实现分析(二)从三个问题导入,分析了Spring ...

  3. 一篇文章说清 webpack、vite、vue-cli、create-vue 的区别

    webpack.vite.vue-cli.create-vue 这些都是什么?看着有点晕,不要怕,我们一起来分辨一下. 先看这个表格: 脚手架 vue-cli create-vue 构建项目 vite ...

  4. wlile、 for循环和基本数据类型及内置方法

    while + else 1.while与else连用 当while没有被关键字break主动结束的情况下 正常结束循环体代码之后执行else的子代码 """ while ...

  5. 操作系统实现-loader

    博客网址:www.shicoder.top 微信:18223081347 欢迎加群聊天 :452380935 大家好呀,终于我们到了操作系统的loader部分了,loader也是操作系统中最重要的一个 ...

  6. Java线程池ThreadPoolExecutor极简教程

    ThreadPoolExecutor 简介 ThreadPoolExecutor 是 java.util.concurrent 包下的一个类,在jdk1.5版本引入,帮助开发人员管理线程并方便地执行并 ...

  7. 《回炉重造 Java 基础》——集合(容器)

    整体框架 绿色代表接口/抽象类:蓝色代表类. 主要由两大接口组成,一个是「Collection」接口,另一个是「Map」接口. 前言 以前刚开始学习「集合」的时候,由于没有好好预习,也没有学好基础知识 ...

  8. 物联网无线数传通信模块设备常见的几种Modbus网关

    物联网无线数传通信常见的几种Modbus网关 以下提到Modbus网关均指Modbus RTU转Modbus TCP,并不涉及对Modbus ASCII数据帧的处理,Modbus ASCII仅支持透明 ...

  9. Visual Studio Installer下载速度为0处理办法

    DNS改为:223.5.5.5即可. 223.5.5.5 下载完成后记得改回来.

  10. .NET中的迭代器(Iterator)

    更新记录 本文迁移自Panda666原博客,原发布时间:2021年6月30日. 一.迭代器介绍 C#2.0开始,我们可以使用迭代器(iterator).编译器自动把我们定义的迭代器生成 可枚举类型 或 ...