寫在前面
最近有很多的粉絲私信我,說自己在面試的時候,老是被人問HashMap的原理,但是在實際的工作中,也只是使用HashMap,從來就沒有關注過它的原來,今天博主本人,根據自己的實際經驗,淺談一下HashMap的實現原理。并附上自己根據原理,手寫的MHashMap,并且還帶上了部分區塊鏈的特征。
JDK7和JDK8中的HashMap
JDK7:數組和鏈式結構 JDK8:數組和鏈式結構,紅黑樹 兩者之間的區別就是,JDK8中加上了紅黑樹。 因為今天是一個HashMap的原理淺析,這里就不附帶講解紅黑樹,后面的博文,我會專門來講解紅黑樹。
正文
現在我開始正式進入我對HashMap講解中來。 HashMap的特征
存儲結構:key,value鍵值對的形式
查詢數據: 1,通過key進行mod(取模),獲取到當前數組對應的node, 2,根據node存放的hash和key對應的hash進行比較,是否一致,如果不一致,則同當前node的下一個node進行比對。 3,還是不一致,就繼續從當前比較的Node取下一個節點進行比較。
存儲數據: 1,對key進行mod計算 2,將數據存放到data[mod]中去 3,如果當前的data[mod]已經有值存在了,則將當前已經存在的對象oldNode,存放到新的Node的next中去
我們定義一個數組,并給給它一個默認的長度
private final static int defaultDataLength = 16;
再創建一個指定長度的數組
private Node[] data = new Node[defaultDataLength];
這里的Node為我們自己定義的一個內部類對象
@Getter
@Setter
static class Node {
private int hashCode;
private Object key;
private Object value;
private Node next;
public static Node instance(int hashCode, Object key, Object value, Node next) {
Node node = new Node();
node.setHashCode(hashCode);
node.setKey(key);
node.setValue(value);
node.setNext(next);
return node;
}
}
它由四個元素組成,當前傳入key的hash值,當前的key,當前的value及下一個對象。
完整代碼
package com.moonl.jvm.utils;
import lombok.Getter;
import lombok.Setter;
import JAVA.io.Serializable;
import java.util.AbstractMap;
import java.util.Map;
import java.util.Set;
public class MHashMap<K, V> {
private final static int defaultDataLength = 16;
private Node[] data = new Node[defaultDataLength];
private Integer previousHashCode = 0;
public V put(K key, V value) {
int hash = hash(key);
int mod = hashMod(key);
if (null == data[mod]) {
data[mod] = Node.instance(hash, key, value, null);
return value;
}
//舊的node緩存
Node oldNode = data[mod];
//新的key,存放到指定位置的數組中去,并將原有節點存放到next中
data[mod] = Node.instance(hash, key, value, oldNode);
return value;
}
public V get(K key) {
Node node = data[hashMod(key)];
//root node hashCode
this.previousHashCode = hash((K) ("root_" + hashMod(key)));
return findKey(node, key);
}
public V findKey(Node node, K key) {
if (null == key) {
return null;
}
if (node == null) {
return null;
}
String chain = "The Previous HashCode:" + previousHashCode + " Now HashCode :" + node.getHashCode();
//傳入的key對應的hash
int hash = hash(key);
//當前節點存儲的hashCode
int hashCode = node.getHashCode();
if (hash == hashCode) {
System.out.println("input key is :" + key + " and hash:" + hashCode);
System.out.println("query key is :" + node.getKey() + " and hash:" + node.getHashCode());
return (V) node.getValue();
}
//當前找到的節點的下一個節點
Node nextNode = node.getNext();
//如果要從下一個節點開始查詢,則當前節點變更為上一個節點
previousHashCode = node.getHashCode();
chain = chain + " Next Node HashCode :" + nextNode.getHashCode();
System.out.println(chain);
return findKey(nextNode, key);
}
public int hash(K key) {
int hashCode = 0;
return key == null ? 0 : key.hashCode();
}
public int hashMod(K key) {
return Math.abs(key.hashCode() % 16);
}
@Getter
@Setter
static class Node {
private int hashCode;
private Object key;
private Object value;
private Node next;
public static Node instance(int hashCode, Object key, Object value, Node next) {
Node node = new Node();
node.setHashCode(hashCode);
node.setKey(key);
node.setValue(value);
node.setNext(next);
return node;
}
}
}
在代碼中,我對根節點,也就是數組節點的記錄方式是"root_"+mod值共同生成的hash // 現在我們開始使用封裝數據(put),并逐步(get)數據
@Test
public void testHashMap() {
// Map<String, Object> maps = new HashMap<String, Object>();
MHashMap<String, Object> zhaoMaps = new MHashMap<String, Object>();
for (int i = 0; i < 1000; i++) {
zhaoMaps.put("趙"+i+"姐","趙穎"+i+"姐 is 250");
}
MHashMap<String, Object> yingMaps = new MHashMap<String, Object>();
for (int i = 0; i < 1000; i++) {
yingMaps.put("大穎"+i+"姐","大穎"+i+"姐 is 250");
}
System.out.println(zhaoMaps.get("趙162姐"));
System.out.println(yingMaps.get("大穎456姐"));
}
輸出的結果是
The Previous HashCode:-925311973 Now HashCode :-914498616 Next Node HashCode :-914499608
The Previous HashCode:-914498616 Now HashCode :-914499608 Next Node HashCode :-914500600
The Previous HashCode:-914499608 Now HashCode :-914500600 Next Node HashCode :-914501592
The Previous HashCode:-914500600 Now HashCode :-914501592 Next Node HashCode :-914502584
The Previous HashCode:-914501592 Now HashCode :-914502584 Next Node HashCode :-914503576
The Previous HashCode:-914502584 Now HashCode :-914503576 Next Node HashCode :-914529368
The Previous HashCode:-914503576 Now HashCode :-914529368 Next Node HashCode :-914530360
The Previous HashCode:-914529368 Now HashCode :-914530360 Next Node HashCode :-914531352
The Previous HashCode:-914530360 Now HashCode :-914531352 Next Node HashCode :-914532344
The Previous HashCode:-914531352 Now HashCode :-914532344 Next Node HashCode :-914533336
The Previous HashCode:-914532344 Now HashCode :-914533336 Next Node HashCode :-914560120
The Previous HashCode:-914533336 Now HashCode :-914560120 Next Node HashCode :-914561112
The Previous HashCode:-914560120 Now HashCode :-914561112 Next Node HashCode :-914562104
The Previous HashCode:-914561112 Now HashCode :-914562104 Next Node HashCode :-914563096
The Previous HashCode:-914562104 Now HashCode :-914563096 Next Node HashCode :-914584424
The Previous HashCode:-914563096 Now HashCode :-914584424 Next Node HashCode :-914590872
The Previous HashCode:-914584424 Now HashCode :-914590872 Next Node HashCode :-914591864
The Previous HashCode:-914590872 Now HashCode :-914591864 Next Node HashCode :-914592856
The Previous HashCode:-914591864 Now HashCode :-914592856 Next Node HashCode :-914614184
The Previous HashCode:-914592856 Now HashCode :-914614184 Next Node HashCode :-914615176
The Previous HashCode:-914614184 Now HashCode :-914615176 Next Node HashCode :-914621624
The Previous HashCode:-914615176 Now HashCode :-914621624 Next Node HashCode :-914622616
The Previous HashCode:-914621624 Now HashCode :-914622616 Next Node HashCode :-914643944
The Previous HashCode:-914622616 Now HashCode :-914643944 Next Node HashCode :-914644936
The Previous HashCode:-914643944 Now HashCode :-914644936 Next Node HashCode :-914645928
The Previous HashCode:-914644936 Now HashCode :-914645928 Next Node HashCode :-914652376
The Previous HashCode:-914645928 Now HashCode :-914652376 Next Node HashCode :-914673704
The Previous HashCode:-914652376 Now HashCode :-914673704 Next Node HashCode :-914674696
The Previous HashCode:-914673704 Now HashCode :-914674696 Next Node HashCode :-914675688
The Previous HashCode:-914674696 Now HashCode :-914675688 Next Node HashCode :-914676680
The Previous HashCode:-914675688 Now HashCode :-914676680 Next Node HashCode :-914703464
The Previous HashCode:-914676680 Now HashCode :-914703464 Next Node HashCode :-914704456
The Previous HashCode:-914703464 Now HashCode :-914704456 Next Node HashCode :-914705448
The Previous HashCode:-914704456 Now HashCode :-914705448 Next Node HashCode :-914706440
The Previous HashCode:-914705448 Now HashCode :-914706440 Next Node HashCode :-914707432
The Previous HashCode:-914706440 Now HashCode :-914707432 Next Node HashCode :-914733224
The Previous HashCode:-914707432 Now HashCode :-914733224 Next Node HashCode :-914734216
The Previous HashCode:-914733224 Now HashCode :-914734216 Next Node HashCode :-914735208
The Previous HashCode:-914734216 Now HashCode :-914735208 Next Node HashCode :-914736200
input key is :趙162姐 and hash:-914736200
query key is :趙162姐 and hash:-914736200
趙穎162姐 is 250
The Previous HashCode:-925311975 Now HashCode :-2010266582 Next Node HashCode :-2010267574
The Previous HashCode:-2010266582 Now HashCode :-2010267574 Next Node HashCode :-2010268566
The Previous HashCode:-2010267574 Now HashCode :-2010268566 Next Node HashCode :-2010269558
The Previous HashCode:-2010268566 Now HashCode :-2010269558 Next Node HashCode :-2010270550
The Previous HashCode:-2010269558 Now HashCode :-2010270550 Next Node HashCode :-2010271542
The Previous HashCode:-2010270550 Now HashCode :-2010271542 Next Node HashCode :-2010296342
The Previous HashCode:-2010271542 Now HashCode :-2010296342 Next Node HashCode :-2010297334
The Previous HashCode:-2010296342 Now HashCode :-2010297334 Next Node HashCode :-2010298326
The Previous HashCode:-2010297334 Now HashCode :-2010298326 Next Node HashCode :-2010299318
The Previous HashCode:-2010298326 Now HashCode :-2010299318 Next Node HashCode :-2010300310
The Previous HashCode:-2010299318 Now HashCode :-2010300310 Next Node HashCode :-2010301302
The Previous HashCode:-2010300310 Now HashCode :-2010301302 Next Node HashCode :-2010302294
The Previous HashCode:-2010301302 Now HashCode :-2010302294 Next Node HashCode :-2010326102
The Previous HashCode:-2010302294 Now HashCode :-2010326102 Next Node HashCode :-2010327094
The Previous HashCode:-2010326102 Now HashCode :-2010327094 Next Node HashCode :-2010328086
The Previous HashCode:-2010327094 Now HashCode :-2010328086 Next Node HashCode :-2010329078
The Previous HashCode:-2010328086 Now HashCode :-2010329078 Next Node HashCode :-2010330070
The Previous HashCode:-2010329078 Now HashCode :-2010330070 Next Node HashCode :-2010331062
The Previous HashCode:-2010330070 Now HashCode :-2010331062 Next Node HashCode :-2010332054
The Previous HashCode:-2010331062 Now HashCode :-2010332054 Next Node HashCode :-2010333046
The Previous HashCode:-2010332054 Now HashCode :-2010333046 Next Node HashCode :-2010355862
The Previous HashCode:-2010333046 Now HashCode :-2010355862 Next Node HashCode :-2010356854
The Previous HashCode:-2010355862 Now HashCode :-2010356854 Next Node HashCode :-2010357846
The Previous HashCode:-2010356854 Now HashCode :-2010357846 Next Node HashCode :-2010358838
The Previous HashCode:-2010357846 Now HashCode :-2010358838 Next Node HashCode :-2010359830
The Previous HashCode:-2010358838 Now HashCode :-2010359830 Next Node HashCode :-2010360822
The Previous HashCode:-2010359830 Now HashCode :-2010360822 Next Node HashCode :-2010361814
The Previous HashCode:-2010360822 Now HashCode :-2010361814 Next Node HashCode :-2010362806
The Previous HashCode:-2010361814 Now HashCode :-2010362806 Next Node HashCode :-2010363798
The Previous HashCode:-2010362806 Now HashCode :-2010363798 Next Node HashCode :-2010385622
The Previous HashCode:-2010363798 Now HashCode :-2010385622 Next Node HashCode :-2010386614
The Previous HashCode:-2010385622 Now HashCode :-2010386614 Next Node HashCode :-2010387606
The Previous HashCode:-2010386614 Now HashCode :-2010387606 Next Node HashCode :-2010388598
The Previous HashCode:-2010387606 Now HashCode :-2010388598 Next Node HashCode :-2010389590
The Previous HashCode:-2010388598 Now HashCode :-2010389590 Next Node HashCode :-2010390582
The Previous HashCode:-2010389590 Now HashCode :-2010390582 Next Node HashCode :-2010391574
The Previous HashCode:-2010390582 Now HashCode :-2010391574 Next Node HashCode :-2010392566
The Previous HashCode:-2010391574 Now HashCode :-2010392566 Next Node HashCode :-2010393558
The Previous HashCode:-2010392566 Now HashCode :-2010393558 Next Node HashCode :-2010394550
The Previous HashCode:-2010393558 Now HashCode :-2010394550 Next Node HashCode :-2010416374
The Previous HashCode:-2010394550 Now HashCode :-2010416374 Next Node HashCode :-2010417366
The Previous HashCode:-2010416374 Now HashCode :-2010417366 Next Node HashCode :-2010418358
The Previous HashCode:-2010417366 Now HashCode :-2010418358 Next Node HashCode :-2010419350
input key is :大穎456姐 and hash:-2010419350
query key is :大穎456姐 and hash:-2010419350
大穎456姐 is 250
通過輸出的日志,我們可以看見,node節點的存儲結構是按照區塊鏈的特性,記錄上個節點的信息和下一個節點的信息關系來存儲數據。
當然,這里我們對Node對象再寫深入一些,加上一些共識的算法,加密解密驗簽的算法,并做節點的共享,那么一個簡單的區塊鏈就完成了。
本文,主要是為了解答粉絲在面試過程中,面試官不停問HashMap原理而編寫的,區塊鏈就不做更多的闡述了。