最新国产好看的视频,伊人天堂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,還對它們進行了測試和底層代碼分析,本文介紹HashMap key和value能否為null,感興趣的朋友跟隨小編一起看看吧

【一】HashMap

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

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

(3)當key為空時,key的hash值為0,所以如果再設置一個值會對原有value進行覆蓋

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

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

對于get()方法

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

【二】HashTable

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

當我們調用put()方法時:

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

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

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

【三】ConcurrentHashMap

結論:key和value都不能為null

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

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

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

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

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

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

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

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

hashmap方法里面,當k==null返回0,所以只要key為null就將Node插入到索引為0的桶當中,那下一個null來了怎么辦?源碼當中寫了,首先判斷這個存在的節(jié)點,如果它們的hashcode相等,下一步判斷key是否相同,這里判斷用到了||,就是地址一樣(都是null也成了),或者equals相同也可以,就進行替換,所以得出結論:hashmap 當中 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));
        //驗證 HashMap的key和value都可以為null
        //當key為空時,key的hash值為0
        map.put(null,null);
        System.out.println(map.containsKey(null));
        System.out.println(map.get(null));
        //當key為空時,key的hash值為0,所以如果再設置一個值會對原有value進行覆蓋
        map.put(null,123);
        System.out.println(map.containsKey(null));
        System.out.println(map.get(null));
        //驗證 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
        //驗證 HashMap的key和value都可以為null
        //當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值時調用單獨的方法,在該方法中會判斷key是否為null,如果是則返回0;

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

相關文章

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

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

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

    SpringSecurity6.x多種登錄方式配置小結

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

    java通過url讀取文件內容示例

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

最新評論

昌江| 哈尔滨市| 和硕县| 海南省| 宣汉县| 铜鼓县| 曲松县| 富蕴县| 远安县| 图片| 蓬安县| 江西省| 沛县| 观塘区| 兴化市| 广河县| 西宁市| 广东省| 河北区| 阜阳市| 盐边县| 中牟县| 绍兴县| 五台县| 凭祥市| 宝清县| 汨罗市| 天津市| 满洲里市| 华容县| 自贡市| 马鞍山市| 宜川县| 云阳县| 乌鲁木齐市| 延长县| 凌海市| 岳普湖县| 香河县| 甘洛县| 宁南县|