最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

深入淺析HashMap key和value能否為null

 更新時間:2025年04月08日 16:57:40   作者:fixAllenSun  
HashMap的key和value可為null,線程不安全,HashTable的key和value均不可為null,線程安全,ConcurrentHashMap在多線程場景下使用,key和value也不能為null,還對它們進(jìn)行了測試和底層代碼分析,本文介紹HashMap key和value能否為null,感興趣的朋友跟隨小編一起看看吧

【一】HashMap

(1)結(jié)論:HashMap對象的key、value值均可為null
HashMap 的 key 和 value 都可以為 null 值。在 Java 中,HashMap 允許 null 作為 key 和 value 的值。當(dāng)插入 null 作為 key 時,它將被存儲在 HashMap 的第一個位置上(即桶數(shù)組的第一個位置),而當(dāng)插入 null 作為 value 時,它可以存儲在任何一個位置上。當(dāng)然,需要注意的是,由于 HashMap 是根據(jù) key 的哈希值來確定存儲位置的,所以插入 null 值作為 key 時需要格外小心,以避免出現(xiàn)哈希沖突導(dǎo)致的問題。

(2)key能否重復(fù)
key值不能重復(fù),若添加key相同的鍵值對,后面的value會自動覆蓋前面的value,但不會報錯

(3)當(dāng)key為空時,key的hash值為0,所以如果再設(shè)置一個值會對原有value進(jìn)行覆蓋

(4)HashMap是線程不安全的,他的key和value都可以為null

HashMap求hash值時,并不是一上來就直接用key值求,他先進(jìn)行了一個判斷,如果為null,hash值為0。

對于get()方法

返回的是null,此時null值不知道是未找到還是對應(yīng)的value值。
這就出現(xiàn)了一個問題:當(dāng)A線程使用containsKey()進(jìn)行判斷時,發(fā)現(xiàn)有這個元素,當(dāng)他調(diào)用get()取這個元素時,B線程加入了進(jìn)來,B線程將這個元素移除掉了,此時A線程取得的值為null,A線程會以為自己取到了這個值,但實(shí)際上此時的null是未找到的null。這樣線程間就有可能出現(xiàn)安全問題。
以至于我們在多線程情況下,使用的是currentHashMap存儲數(shù)據(jù),它的key和balue都是不能為null的。

【二】HashTable

(1)結(jié)論:HashTable對象的key、value值均不可為null
HashTable是線程安全的,HashTable對象的key、value值均不可為null。

當(dāng)我們調(diào)用put()方法時:

為什么要一來就判斷value值不能為null呢?這就要看到get()方法:

發(fā)現(xiàn)沒有,如果value值能為null,那么我傳入對應(yīng)的key值,他找到了返回的是value值,也就是null,當(dāng)找不到時,他也返回的是null。找到找不到返回值都是null,這怎么分辨?

所以,HashTable的key和value值都不能為null。

【三】ConcurrentHashMap

結(jié)論:key和value都不能為null

假定ConcurrentHashMap也可以存放value為null的值。那不管是HashMap還是ConcurrentHashMap調(diào)用map.get(key)的時候,如果返回了null,那么這個null,都有兩重含義:
(1)這個key從來沒有在map中映射過。
(2)這個key的value在設(shè)置的時候,就是null。

但是hashmap可以通過 containskey來確定到底是哪一個原因!

而多線程情況下,ConcurrentHashMap中的value不能為null

原因如下:
ConcurrentHashMap的使用場景為多線程。用反證法來推理,假設(shè)concurrentHashMap允許存放值為null的value。這時有A、B兩個線程。線程A調(diào)用concurrentHashMap.get(key)方法,返回為null,我們還是不知道這個null是沒有映射的null還是存的值就是null。

我們假設(shè)此時返回為null的真實(shí)情況就是因?yàn)檫@個key沒有在map里面映射過。那么我們可以用concurrentHashMap.containsKey(key)來驗(yàn)證我們的假設(shè)是否成立,我們期望的結(jié)果是返回false。

但是在我們調(diào)用concurrentHashMap.get(key)方法之后,containsKey方法之前,有一個線程B執(zhí)行了concurrentHashMap.put(key,null)的操作。那么我們調(diào)用containsKey方法返回的就是true了。這就與我們的假設(shè)的真實(shí)情況不符合了。也就是上面說的二義性。

上面也說了,hashmap可以key為null,但可以存在多個null嗎?

static final int hash(Object key) {
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

hashmap方法里面,當(dāng)k==null返回0,所以只要key為null就將Node插入到索引為0的桶當(dāng)中,那下一個null來了怎么辦?源碼當(dāng)中寫了,首先判斷這個存在的節(jié)點(diǎn),如果它們的hashcode相等,下一步判斷key是否相同,這里判斷用到了||,就是地址一樣(都是null也成了),或者equals相同也可以,就進(jìn)行替換,所以得出結(jié)論:hashmap 當(dāng)中 key為null的只有一個!??!

【四】測試代碼

public class Test {
	public static void main(String[] args) {
		Map<String, String> map = new HashMap<String, String>();//HashMap對象
		Map<String, String> tableMap = new Hashtable<String, String>();//HashTable對象
		map.put(null, null);
		System.out.println("hashMap的[key]和[value]均可以為null:" + map.get(null));
		try {
			tableMap.put(null, "3");
			System.out.println(tableMap.get(null));
		} catch (Exception e) {
			System.out.println("【ERROR】:hashTable的[key]不能為null");
		}
		try {
			tableMap.put("3", null);
			System.out.println(tableMap.get("3"));
		} catch (Exception e) {
			System.out.println("【ERROR】:hashTable的[value]不能為null");
		}
	}
}
import java.util.HashMap;
import java.util.Hashtable;
public class TestMap {
    public static void main(String[] args){
        HashMap<Integer,Integer> map = new HashMap<>();
        System.out.println(map.containsKey(null));
        System.out.println(map.get(null));
        //驗(yàn)證 HashMap的key和value都可以為null
        //當(dāng)key為空時,key的hash值為0
        map.put(null,null);
        System.out.println(map.containsKey(null));
        System.out.println(map.get(null));
        //當(dāng)key為空時,key的hash值為0,所以如果再設(shè)置一個值會對原有value進(jìn)行覆蓋
        map.put(null,123);
        System.out.println(map.containsKey(null));
        System.out.println(map.get(null));
        //驗(yàn)證 Hashtable
        Hashtable<Integer,Integer> hashtable = new Hashtable<>();
        System.out.println(hashtable.containsKey(null));
        System.out.println(hashtable.get(null));
        //HashTable是線程安全的,key和value都不可以為null
        //HashMap是線程不安全的,他的key和value都可以為null
        //驗(yàn)證 HashMap的key和value都可以為null
        //當(dāng)key為空時,key的hash值為0
        hashtable.put(null,null);
        System.out.println(hashtable.containsKey(null));
        System.out.println(hashtable.get(null));
    }
}

執(zhí)行效果

false
null
true
null
true
123
Exception in thread "main" java.lang.NullPointerException
    at java.util.Hashtable.containsKey(Hashtable.java:336)
    at com.itheima.test.TestMap.main(TestMap.java:31)

【五】底層代碼分析

【1】Hashtable

    public synchronized V put(K key, V value) {
        // 確保value不為空。這句代碼過濾掉了所有value為null的鍵值對。因此Hashtable不能
        // 存儲value為null的鍵值對
        if (value == null) {
            throw new NullPointerException();
        }
        // 確保key在table數(shù)組中尚未存在。
        Entry<?,?> tab[] = table;
        int hash = key.hashCode(); //在此處計算key的hash值,如果此處key為null,則直接拋出空指針異常。
        int index = (hash & 0x7FFFFFFF) % tab.length;
        @SuppressWarnings("unchecked")
        Entry<K,V> entry = (Entry<K,V>)tab[index];
        for(; entry != null ; entry = entry.next) {
            if ((entry.hash == hash) && entry.key.equals(key)) {
                V old = entry.value;
                entry.value = value;
                return old;
            }
        }
        addEntry(hash, key, value, index);
        return null;
    }

Hashtable的源碼可以看出,如果value=null直接拋出空指針異常;而使用key.hashCode()不允許key=null,所以無論是key還是value都不能是null。而在HashMap中并沒有這樣的限制,key和value允許使用null。

【2】HashMap

public V put(K key, V value) {
        return putVal(hash(key), key, value, false, true);
    }
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
        else {
            Node<K,V> e; K k;
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
            else if (p instanceof TreeNode)
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            else {
                for (int binCount = 0; ; ++binCount) {
                    if ((e = p.next) == null) {
                        p.next = newNode(hash, key, value, null);
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                            treeifyBin(tab, hash);
                        break;
                    }
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        break;
                    p = e;
                }
            }
            if (e != null) { // existing mapping for key
                V oldValue = e.value;
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
                afterNodeAccess(e);
                return oldValue;
            }
        }
        ++modCount;
        if (++size > threshold)
            resize();
        afterNodeInsertion(evict);
        return null;
    }

HashMap計算key的hash值時調(diào)用單獨(dú)的方法,在該方法中會判斷key是否為null,如果是則返回0;

到此這篇關(guān)于深入淺析HashMap key和value能否為null的文章就介紹到這了,更多相關(guān)HashMap key和value能否為null內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • IntelliJ IDEA優(yōu)化配置的實(shí)現(xiàn)

    IntelliJ IDEA優(yōu)化配置的實(shí)現(xiàn)

    這篇文章主要介紹了IntelliJ IDEA優(yōu)化配置的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • SpringSecurity6.x多種登錄方式配置小結(jié)

    SpringSecurity6.x多種登錄方式配置小結(jié)

    SpringSecurity6.x變了很多寫法,本文就來介紹一下SpringSecurity6.x多種登錄方式配置小結(jié),具有一定的參考價值,感興趣的可以了解一下
    2023-12-12
  • java通過url讀取文件內(nèi)容示例

    java通過url讀取文件內(nèi)容示例

    這篇文章主要介紹了java通過url讀取文件內(nèi)容示例,大家參考使用吧
    2014-01-01
  • java實(shí)現(xiàn)順時針打印矩陣

    java實(shí)現(xiàn)順時針打印矩陣

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)順時針打印矩陣的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-03-03
  • SpringBoot配置Tomcat容器、Jetty容器、Undertow容器全過程

    SpringBoot配置Tomcat容器、Jetty容器、Undertow容器全過程

    Spring Boot默認(rèn)集成的三大容器:Tomcat、Jetty和Undertow,Tomcat是輕量級Servlet容器,Jetty是開源的Servlet容器,Undertow是高性能Web服務(wù)器,Tomcat和Jetty在性能和內(nèi)存使用方面都優(yōu)于Undertow,但在并發(fā)量高的情況下,Undertow的性能更優(yōu)
    2025-11-11
  • java環(huán)境中的JDK、JVM、JRE詳細(xì)介紹

    java環(huán)境中的JDK、JVM、JRE詳細(xì)介紹

    這篇文章主要介紹了java環(huán)境中的JDK、JVM、JRE詳細(xì)介紹的相關(guān)資料,對于初學(xué)者還是有必要了解下,細(xì)致說明他們是什么,需要的朋友可以參考下
    2016-11-11
  • Elasticsearch?自動重啟腳本創(chuàng)建實(shí)現(xiàn)

    Elasticsearch?自動重啟腳本創(chuàng)建實(shí)現(xiàn)

    這篇文章主要為大家介紹了Elasticsearch?自動重啟腳本創(chuàng)建實(shí)現(xiàn)詳解分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-08-08
  • idea的注釋不可編輯,變成了只讀模式的問題及解決

    idea的注釋不可編輯,變成了只讀模式的問題及解決

    IDEA注釋在編輯后再次打開時可能會變成只讀模式,無法編輯,此時只需點(diǎn)擊注釋旁的鉛筆圖標(biāo)即可再次編輯,若要永久取消此功能,需在設(shè)置中禁ReaderMode模式,并取消勾選“EnableReaderMode”選項(xiàng)
    2026-05-05
  • SpringBoot中@Scheduled實(shí)現(xiàn)服務(wù)啟動時執(zhí)行一次

    SpringBoot中@Scheduled實(shí)現(xiàn)服務(wù)啟動時執(zhí)行一次

    本文主要介紹了SpringBoot中@Scheduled實(shí)現(xiàn)服務(wù)啟動時執(zhí)行一次,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-08-08
  • 使用Stargate訪問K8ssandra的過程之Springboot整合Cassandra

    使用Stargate訪問K8ssandra的過程之Springboot整合Cassandra

    這篇文章主要介紹了使用Stargate訪問K8ssandra的過程之Springboot整合Cassandra,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-10-10

最新評論

宁晋县| 静乐县| 休宁县| 昌黎县| 阿拉善左旗| 宿州市| 鹤峰县| 清徐县| 天气| 蓝田县| 大关县| 姚安县| 郓城县| 开原市| 台北市| 青州市| 泽州县| 长沙市| 岫岩| 会理县| 定兴县| 南充市| 彭水| 铜山县| 桃源县| 明星| 岱山县| 桑植县| 舟曲县| 卓资县| 邮箱| 沭阳县| 余干县| 永丰县| 都昌县| 兰考县| 弋阳县| 星子县| 香格里拉县| 上虞市| 永年县|