HashTable,ConcurrentHashMap,ArrayList,LinkedListHashtMap等值对存储null以及二义性的深入研究
创始人
2024-05-29 03:13:27
0

本文是自己研究的,如果有任何疑问和补充,请您在评论区指正好嘛,我会立刻修改,以免误导他人.

如果您觉得本文质量不错,可以点个赞和关注一下好嘛.
如果您需要引用本文章的内容,请附加链接,谢谢.

问题描述:

为什么HashTable,ConcurrentHashMap不能保存null键和null值
为什么ArrayList ,LinkedList,甚至是HashMap都允许加入null键和值

博客概述

本文从设计思路到源码进行讲解.下面是概述
HashMap存在二义性 ----> ConcurrentMap,HashTable为什么不存在二义性 ---- > 二义性由 返回值 null ,不能代表元素的存在或者不存在引起 ----> 引申部分 : ArrayList,LinkedList 存在不存在二义性

HashMap能存储null-null,但是有二义性

首先要了解HashMap存在二义性.
HashMap能存储key == null, 也能存储 value == null

二义性是什么先看 get方法,get返回值有两种,一种是 key的值, 还有一种就是 null ,null 有两种含义,不存在该key 以及 存在该 key,但是存的值为 null,这就是二义性
下面来看方法

    public V get(Object key) {Node e;// 这里是关键哦,getNode后,会返回Node节点(里面保存了k-v),也就是说不存在的节点,返回的是null,没有异议吧.// 如果存在呢,也就是找到了一个e ,e != null ,e里面保存了k - v, 也就是返回 e.value 没问题吧,那么假如我value就是null 呢// 这里就出现了,如果没有这个Node,那么e == null,如果有Node,但是 value == null,返回的也是 null .//二义性就是,寻找Node的时候,找到了,其value == null,就返回null,找不到也返回null,有没有这个元素,都有可能返回 null,这就是二义性,即 null 代表两种状态,有歧义return (e = getNode(hash(key), key)) == null ? null : e.value;}

这里很简单,就是找到了返回元素,没找到返回null

    final Node getNode(int hash, Object key) {Node[] tab; Node first, e; int n; K k;if ((tab = table) != null && (n = tab.length) > 0 &&(first = tab[(n - 1) & hash]) != null) {if (first.hash == hash && // always check first node((k = first.key) == key || (key != null && key.equals(k))))return first;if ((e = first.next) != null) {if (first instanceof TreeNode)return ((TreeNode)first).getTreeNode(hash, key);do {if (e.hash == hash &&((k = e.key) == key || (key != null && key.equals(k))))return e;} while ((e = e.next) != null);}}return null;}

看到上面,你会觉得,二义性就是 通过 get() 方法的返回值,如果返回值是 null 无法判断出是否一定存在该元素.
但是,如果你觉得这是他设计的不好,或者是我讲错了.那你想想,这个"Bug"能解决吗,是否可以通过 contains(key) 方法,也就是说可以通过 contains 来判断是否存在该 key 行不行.

来看看contains方法,
这里可以解决二义性的,因为这里返回的是 boolean ,存在即存在,不存在即 false

    public boolean containsKey(Object key) {return getNode(hash(key), key) != null;}
    public boolean containsValue(Object value) {Node[] tab; V v;if ((tab = table) != null && size > 0) {for (int i = 0; i < tab.length; ++i) {for (Node e = tab[i]; e != null; e = e.next) {if ((v = e.value) == value ||(value != null && value.equals(v)))return true;}}}return false;}

有趣的理解:
当 get(key) 的结果为 null 时, 该 key 的存在或者不存在问题类似于薛定谔的猫(如果key存在,这个null就是key的值,如果key不存在,这个 null 只代表了不存在这个key),只有你 containsKey() 之后,才能判断存在这个 key

案例演示:

public class HashMapTest {public static void main(String[] args) {HashMap map = new HashMap<>();System.out.println("put方法,该方法返回null代表的是没有重复的key, 非null是返回的代表被覆盖的值,结果" + map.put("ggzx", null));System.out.println("get方法返回值,null 可以代表值为 null,也可能代表 不存在,我尝试获取,但结果  " + map.get("ggzx"));System.out.println(map.containsKey("ggzx"));System.out.println(map.containsValue(null));}
}
结果:
put方法,该方法返回null代表的是没有重复的key, 非null是返回的代表被覆盖的值,结果null
get方法返回值,null 可以代表值为 null,也可能代表 不存在,我尝试获取,但结果  null
true
true

看一看第二个输出:
如果你知道自己插入了数据,此时null代表了什么
如果你不知道自己插入了什么数据,这个时候你可以断定, null 是值 还是代表不存在.
如果你调用 cotainsKeys() ,能否能判断存在该key吗?

为什么有二义性还要搞

你已经了解了HashMap其实是存在二义性,但是也能够解决,在能解决的基础上,能保存 null-null,感觉也还行对吧.至少能表达一种状态,比如说存储 className --> null ,的情况,null 能代表不存在该 class

为什么HashTable和ConcurrentHashMap不能?

为啥,因为设计者都说了啊,他不想在并发过程中存在这个二义性问题!!!,不过这里我还想冒昧的看看,如果能保存,是否能够用containsKey()来解决

首先来看,Concurrent和HashTable 不能存储 null - null 的证据哇
ConcurrentHashMap#V putVal(K key, V value, boolean onlyIfAbsent)

	    final V putVal(K key, V value, boolean onlyIfAbsent) {// 对于ConcucrrentHashMap, 如果 key || value  == null,都会直接判处if (key == null || value == null) throw new NullPointerException();...本文讲null的存储的,又不讲源码,不给你看很多return null;
    public synchronized V put(K key, V value) {// 如果value == null ,直接抛出异常if (value == null) {throw new NullPointerException();}// Makes sure the key is not already in the hashtable.Entry tab[] = table;// 如果 key == null,就抛出异常了,不过我也不知道为什么不检测,而需要运行时遇到异常抛出去int hash = key.hashCode();... 这部分不给你看了addEntry(hash, key, value, index);return null;}

好了,目前为止,你已经了解了,他们俩,都不能存储 key == null 或者 value == null.
不能存储 null ,返回值如果为 null ,肯定代表不存在了对吧,此时就没有二义性

看一看ArrayList吧

先看看ArrayList# E get(int index)
这里压根就不存在二义性哇,我传入一个索引,索引只有两个状态,无效的和有效的.结果不存在二义性,如果返回 null 呢?代表的就是存储的 null 呗,没有 null 代表不存在一说

    public E get(int index) {// 检查是否越界rangeCheck(index);// 直接返回return elementData(index);}

再看看ArrayList#boolean add(E e)
仔细看看返回的是啥,boolean,加入成功就是成功,失败就是失败,也不会返回null.
第二个重载方法,直接 void 了,还有啥二义性可言

	// 加入元素public boolean add(E e) {ensureCapacityInternal(size + 1);  // Increments modCount!!elementData[size++] = e;return true;}// 重载方法public void add(int index, E element) {rangeCheckForAdd(index);ensureCapacityInternal(size + 1);  // Increments modCount!!System.arraycopy(elementData, index, elementData, index + 1,size - index);elementData[index] = element;size++;}

下面再看看 LinkedList 吧
存入null之前之后,都是返回的 null ,也无法判断,是否是存在key呢,还是不存在key呢

public class LinkedListTest {public static void main(String[] args) {LinkedList list = new LinkedList<>();System.out.println(list.peekLast());list.add(null);list.add(null);list.add(null);list.add(null);System.out.println(list.peekLast());}
}
结果:
null
null

文章结束

最主要的前面的部分,即HashTable,ConcurrentHashMap和HashMap,后面的可以用于拓展吧.
如果你有问题,您可以在评论区进行评论.
你都看到这里了,不打算点个赞和关注嘛

上一篇:【Java】JVM

下一篇:对跳表的深入理解

相关内容

热门资讯

洛克王国不倒叮当 洛克王国不倒叮当好不容易抓个好点的。。性格是保守的。。郁闷了一般稀有宠物的天赋都很高,不到叮当,还不...
不是善茬歇后语下一句 不是善茬歇后语下一句张飞胡敬德剃了胡子——都也不是善茬张飞胡敬德剃胡子一都不是善茬都不是善茬,谁也不...
《有钱没钱回家过年》到底是谁唱... 《有钱没钱回家过年》到底是谁唱的?怎么有好多个版本?请大家帮忙找一下关于这首歌的详细介绍,最近好像流...
傲视天地 里外城的精炼该怎么弄... 傲视天地 里外城的精炼该怎么弄?楼上正解。。没啥可补充了。。。是个很靠谱的提升石头产出的东西亲爱的玩...
《安徒生童话》中有哪个故事中的... 《安徒生童话》中有哪个故事中的主人公最奇怪《安徒生童话》中,**依达**是最奇怪的角色。《小猪倌》。...
悲莫悲兮生别离,乐莫乐兮新相知... 悲莫悲兮生别离,乐莫乐兮新相知啥意思在悲伤啊莫过于活生生的别离,再快乐啊莫过于新相交的知己。
听的多音字是什么 听的多音字是什么听拼音tīng释义1.用耳朵接受声音:~力。~写。~觉。聆~。洗耳恭~。2.顺从,接...
★求最终幻想13男女主角的名字... ★求最终幻想13男女主角的名字!男主很高很帅,戴一个黑色帽子,黄头发;女主很小巧可爱,头发歪着梳的男...
泡沫之夏小说中的洛熙花心吗 泡沫之夏小说中的洛熙花心吗洛熙很专一很痴情很专一很痴情
翻身乐队免费的吗 翻身乐队免费的吗免费。翻身乐队是深圳的一个乐队,一群喜欢音乐的人相约深圳,每周在路边免费路演。
求小说 男女主高中相爱 男主车... 求小说 男女主高中相爱 男主车祸失忆 女主生了个宝宝 男主姓盛 后来男主受伤了 被女主救了求小说 男...
男生是不是都喜欢比较柔弱的女生... 男生是不是都喜欢比较柔弱的女生?柔弱的女生可以激发男生的保护欲,男生一般特别爱表现自己,特别是展现他...
相比其他作品,为什么没有人翻拍... 相比其他作品,为什么没有人翻拍金庸的《连城诀》?因为书中确实很现实,大多数人不喜欢接受现实,都是带着...
“存”繁体字怎么写? “存”繁体字怎么写?”存“字的繁体字即为简体写法”存“,读音”cún“。
三人成虎的意思 三人成虎的意思三人成虎的意思是:有三个人谎报市上有虎,听者就信以为真。比喻讹传一再重复,就可能以假充...
为什么男孩子总是欺骗女孩子? 为什么男孩子总是欺骗女孩子?不管是善意还是恶意的,难道欺骗是你们的爱好吗? 难道这样女孩子就是你的了...
活着的歌词 活着的歌词 《活着》 演唱:郝云 词曲:郝云每天站在高楼上看着地上的小蚂蚁它们的头很大它们的...
给侄女起名字 给侄女起名字大家好,我哥叫叶三杰,嫂子叫赵娟,嫂子在正月初5下午13点给偶家添一千金,想起个名。谢谢...
孔雀东南飞,到底是什么意思,有... 孔雀东南飞,到底是什么意思,有什么寓意?不能棒打鸳鸯呀《孔雀东南飞》是一个爱情故事,原文是表达两人的...
齐秦的女儿,儿子 齐秦的女儿,儿子做到不抱怨 最重要的一条 就是不要在乎 你都不放在心上!就不会在乎...