1. 程式人生 > >java.util.HashMap原始碼初探

java.util.HashMap原始碼初探

對於一個儲存類的分析,無非從兩點入手:儲存用的資料結構,儲存的執行機制。

資料結構:

陣列

    /**
     * The table, resized as necessary. Length MUST Always be a power of two.
     */
    transient Entry[] table;

Entry

連結串列格式。

也即,HashMap中採用的是“連結法”來處理碰撞問題的。

執行機制:

put、get

put方法

    public V put(K key, V value) {
        if (key == null)
            return putForNullKey(value);
        int hash = hash(key.hashCode());
        int i = indexFor(hash, table.length);
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }

        modCount++;
        addEntry(hash, key, value, i);
        return null;
    }

get方法
    public V get(Object key) {
        if (key == null)
            return getForNullKey();
        int hash = hash(key.hashCode());
        for (Entry<K,V> e = table[indexFor(hash, table.length)];
             e != null;
             e = e.next) {
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
                return e.value;
        }
        return null;
    }

可以看出,重要的一句程式碼為:
if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
這句程式碼的作用是判斷兩個Key物件是否“相同”,這裡的相同的意思是指兩個Key完全可以不分彼此,可以作為同一個Key使用。

在put方法中,如果兩個Key的hashCode相同,且equals符合,這裡是把原有的的value替換成新的value。

測試程式碼:

package test.junit;

import java.util.HashMap;

import junit.framework.TestCase;

/**
 * HashMap中判斷兩個Key是否相同:先判斷hashCode,在判斷是否equals
 * e.hash == hash && ((k = e.key) == key || key.equals(k))
 * @author xuefeng
 *
 */
public class HashMapTest extends TestCase {
	
	/**
	 * v1和v4的hashCode相同,但是equals不符合,所以v1和v4會組成一個連結串列。
	 */
	public void testKey1() {
		HashMap<Key, Value> map = new HashMap<Key, Value>();
		Key k1 = new Key(1);
		Key k4 = new Key(4);
		Value v1 = new Value(1);
		Value v4 = new Value(4);
		
		map.put(k1, v1);
		map.put(k4, v4);
		
		assertEquals(v1, map.get(k1));
		assertEquals(v4, map.get(k4));
	}
	
	/**
	 * v1和v4的hashCode相同,而且equals也符合,所以v1會被v4替換掉,k1和k4指向同一個v4。
	 */
	public void testKey2() {
		HashMap<Key2, Value> map = new HashMap<Key2, Value>();
		Key2 k1 = new Key2(1);
		Key2 k4 = new Key2(4);
		Value v1 = new Value(1);
		Value v4 = new Value(4);
		
		map.put(k1, v1);
		map.put(k4, v4); // 這裡會替換掉v1
		
//		assertEquals(v1, map.get(k1));
		assertEquals(v4, map.get(k1));
		assertEquals(v4, map.get(k4));
	}
}

class Key {
	public int m;
	
	public Key(int m) {
		this.m = m;
	}
	
	@Override
	public int hashCode() {
		return m%3;
	}
}

class Value {
	public int m;
	
	public Value(int m) {
		this.m = m;
	}
}

class Key2 {
	public int m;
	
	public Key2(int m) {
		this.m = m;
	}
	
	@Override
	public int hashCode() {
		return m%3;
	}
	
	@Override
	public boolean equals(Object obj) {
		if(obj == null || !(obj instanceof Key2)) return false;
		
		Key2 other = (Key2)obj;
		
		return this.hashCode() == other.hashCode();
	}
}


相關推薦

java.util.HashMap原始碼初探

對於一個儲存類的分析,無非從兩點入手:儲存用的資料結構,儲存的執行機制。 資料結構: 陣列 /** * The table, resized as necessary. Length MUST Always be a power of two.

JDK1.8原始碼(三)——java.util.HashMap

什麼是雜湊表? 在討論雜湊表之前,我們先大概瞭解下其他資料結構在新增,查詢等基礎操作執行效能   陣列:採用一段連續的儲存單元來儲存資料。對於指定下標的查詢,時間複雜度為O(1);通過給定值進行查詢,需要遍歷陣列,逐一比對給定關鍵字和陣列元素,時間複雜度為O(n),當然,對於有序陣列,則可採用二分查詢

java.util.HashMap

不同 resize clas corporate nbsp possible com 10個 eap HashMap 如何實現? put 做了什麽? get 做了什麽? 初始化容量,滿載率,擴展? hash? 類似的結構及相似處,不同點? load factor 滿

Can not deserialize instance of java.util.HashMap out of VALUE_NUMBER_INT token

Can not deserialize instance of java.util.HashMap out of VALUE_NUMBER_INT token 異常資訊 測試環境一直提示上述異常 本地模擬 public class testzhu

圖解java.util.concurrent原始碼(三) Reentrantlock && Semaphore

引言 Reentrantlock和Semaphore分別是AQS在獨佔模式和共享模式下經典的實現,在理解AQS的情況下看這兩個類的程式碼會感到非常簡單,如果還沒理解AQS的話,建議先讀我這個系列的第一篇文章 複習AQS 回憶一下AQS,AQS中維護了一個st

JavaHashMap原始碼分析——基本概念

在JDK1.8後,對HashMap原始碼進行了更改,引入了紅黑樹。 在這之前,HashMap實際上就是就是陣列+連結串列的結構,由於HashMap是一張雜湊表,其會產生雜湊衝突,為了解決雜湊衝突,HashMap採用了開鏈法,即對於用物件hashCode值計算雜湊

JavaHashMap原始碼分析——常用方法詳解

上一篇介紹了HashMap的基本概念,這一篇著重介紹HasHMap中的一些常用方法:put()get()**resize()** 首先介紹resize()這個方法,在我看來這是HashMap中一個非常重要的方法,是用來調整HashMap中table的容量的,在很多操作中多需要重新計算容量。原始碼如下: 1

java.util.HashMap.remove()方法例項

remove() 方法用於從該對映中移除了對映指定鍵(如果存在)。 宣告 以下是java.util.HashMap.remove()方法的宣告。 public V remove(Object key) 引數 key–這是其對映關係要從對映中移除的鍵對應值。 返回值 該方法呼叫返回與key相關

牽一髮而動全身 Parameter Maps collection does not contain value for java.util.HashMap 如何坑爹的

今天開發專案,費了不少勁終於寫好整套BUG,滿心歡喜的去測試,然後啟動tomcat,正常,開啟網站登入,Boom,炸的一臉懵逼,竟然登入不上去了,趕緊看控制檯,發現報了這個錯 Parameter Maps collection does not contain value f

Java 併發工具包-java.util.concurrent-原始碼jdk1.7全面解析

先來看看類圖: 其實從類圖我們能發現concurrent包(除去java.util.concurrent.atomic 和 java.util.concurrent.locks)中的內容並沒有特別多,大概分為四類:BlockingQueue阻塞佇列體系、Executor

JavaHashMap原始碼淺析

在Java編碼中可以說HashMap的使用是可以說是無處不在的,對於HashMap的實現原理沒有去過多深入學習,一直停留在使用階段。現在想來還是要一探HashMap的實現原理,不要一味的只是停留在使用階段。而且HashMap的原理在很多面試中都會問到哦,所以弄清

java.util.Optional原始碼解讀

/* * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license ter

java.utl.HashMap 原始碼解讀

目錄 1. HashMap容器預設的初始化大小為16  2. HashMap預設的負載因子為0.75  3. HashMap的儲存容器為陣列  4. JDK8以後, 如果相同HasHcode所在位置的Node連結串列長度超過指定閾值會自動轉換成Tre

細說java.util.HashMap

HashMap是我們最常用的類之一,它實現了hash演算法,雖然使用很簡單,但是其實現有很多值得研究的地方。 HashMap儲存的是key-value形式的鍵值對,這個鍵值對在實現中使用一個靜態內部類Entry來表示,它儲存了key、value、hash值、以及在hash衝

resultMap type型別 java.util.HashMap與pojo類的區別

MyBatis的返回引數型別分兩種1. 對應的分類為:1.1.resultMap:1.2.resultType:2 .對應返回值型別:2.1.resultMap:結果集2.2.resultType:int,string ,long ,class 可以返回HashMap1.re

JavaHashMap原始碼解讀

HashMap一直是陣列加連結串列的資料結構,在陣列的某個下標位置,有多次碰撞,則使用連結串列資料結果儲存。在jdk1.8中,引入了紅黑二叉查詢樹的資料結構。剛開始產生碰撞時,碰撞處仍然是連結串列結構,當連結串列的長度超過原始碼設定值8以後,該處的連結串列將轉為

java.util.HashMap(JDK8)

基本概念1. HashMap 是基於雜湊實現,每一個元素都是一個key-value2. 一般情況下通過單鏈表解決衝突問題;極端情況(所有key相同)使用balance tree 解決。3. 容量不足,自動增長4. 非執行緒安全Table/** * The table

Java原始碼分析——java.util工具包解析(三)——HashMap、TreeMap、LinkedHashMap、Hashtable類解析

    Map,中文名字對映,它儲存了鍵-值對的一對一的關係形式,並用雜湊值來作為存貯的索引依據,在查詢、插入以及刪除時的時間複雜度都為O(1),是一種在程式中用的最多的幾種資料結構。Java在java.util工具包中實現了Map介面,來作為各大

JDK原始碼閱讀-------自學筆記(二十三)(java.util.LinkedList 初探 自定義講解)

1、LinkedList簡介 (1) 底層用雙向連結串列實現的儲存 (2) 查詢效率低,頻繁增刪效率高,執行緒不安全是其主要特點 (3) 常用單詞Node/Entry表示一個節點,或稱為條項,詞條(形容節點的樣子) (4) 連結串列由三部分組成:前一個節點,本節點儲存的資料,後一個節點 2、LinkedL

JAVA常用集合原始碼分析:HashMap

我們這篇文章就來試著分析下 HashMap 的原始碼,由於 HashMap 底層涉及到太多方面,一篇文章總是不能面面俱到,所以我們可以帶著面試官常問的幾個問題去看原始碼: 瞭解底層如何儲存資料的 HashMap 的幾個主要方法 HashMap 是如何確定元素儲存位置的以及如何處