HashSet底层HashMap源码分析

在看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叫“存在”了吧?因为张麻子说过,你和钱对我都不重要,有你,对我很重要。

posted @   吉比特  阅读(47)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
今天是植树节,要保护环境呀
点击右上角即可分享
微信分享提示
主题色彩