# [çåä¸ç个人空é´](https://scm-git.github.io/)
## HashMapæºç åæ
HashMap.java
```java
public class HashMap extends AbstractMap
implements Map, Cloneable, Serializable {
// HashMapçé»è®¤å®¹éï¼tableæ°ç»çé»è®¤é¿åº¦
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
// tableçæå¤§å®¹éï¼è¯¥å®¹é表示tableæ°ç»çé¿åº¦ï¼å¹¶ä¸æ¯è£
å
¥çå
ç´ ä¸ªæ°ï¼å 为ä¸ä¸ªä½ç½®ä¸å¯ä»¥æå¤ä¸ªå
ç´ (Node),æ¯ä¸ªNodeçnext屿§ä¼ä¿åå
¶åé¢çNodeçå°åï¼å æ¤ä¸ä¸ªç´¢å¼ä½ç½®ä¸å¯è½ä¸æ¢ä¸ä¸ªNode
static final int MAXIMUM_CAPACITY = 1 << 30;
// é»è®¤å è½½å åï¼å¦ææ²¡æè®¾ç½®å è½½å åæ¶ï¼ä½¿ç¨è¯¥å¼
static final float DEFAULT_LOAD_FACTOR = 0.75f;
/**
* The bin count threshold for using a tree rather than list for a
* bin. Bins are converted to trees when adding an element to a
* bin with at least this many nodes. The value must be greater
* than 2 and should be at least 8 to mesh with assumptions in
* tree removal about conversion back to plain bins upon
* shrinkage.
*/
static final int TREEIFY_THRESHOLD = 8;
/**
* The bin count threshold for untreeifying a (split) bin during a
* resize operation. Should be less than TREEIFY_THRESHOLD, and at
* most 6 to mesh with shrinkage detection under removal.
*/
static final int UNTREEIFY_THRESHOLD = 6;
/**
* The smallest table capacity for which bins may be treeified.
* (Otherwise the table is resized if too many nodes in a bin.)
* Should be at least 4 * TREEIFY_THRESHOLD to avoid conflicts
* between resizing and treeification thresholds.
*/
static final int MIN_TREEIFY_CAPACITY = 64;
/* ---------------- Fields -------------- */
// å卿æé®å¼å¯¹çæ°ç»ï¼ææçé®å¼å¯¹è¢«å
è£
æNodeæ¾å
¥è¯¥æ°ç»ä¸
transient Node[] table;
/**
* Holds cached entrySet(). Note that AbstractMap fields are used
* for keySet() and values().
*/
transient Set> entrySet;
// Key-Valueé®å¼å¯¹çæ°é
transient int size;
// HashMapçç»æä¿®æ¹æ¬¡æ°ï¼æ¯å¦put, removeçæ¹æ³ä¼æ¯æ¬¡å¢å 该å¼
transient int modCount;
// éå¼: threshold = capacity * loadFactor; å½å
ç´ ä¸ªæ°è¾¾å°é弿¶ï¼HashMapè°ç¨resize()æ¹æ³æ©å®¹ï¼æ¯æ¬¡æ©å®¹é½ä¼å°å®¹éæ©å¤§ä¸ºåæ¥ç两åï¼æ©å®¹æ¶ä¼éæ°å¯¹åæ¥çå
ç´ è¿è¡å®ä½ï¼å¹¶å°æ°çç´¢å¼ä½ç½®æå忥çå
ç´
int threshold;
// å è½½å åï¼ç¨äºè®¾ç½®HashMapçæ©å®¹éå¼threshold; 表示å½Node个æ°è¾¾å°å¤æ»¡çç¨åº¦æ¶ï¼ä¼æ©å®¹HashMap
// å½±åHashMapç两个å ç´ ï¼åå§å®¹é(initialCapacity)åå è½½å å(loadFactor)ãåå§å®¹éæ¯æé æ¹æ³ä¸ç´æ¥æå®ï¼å¦æä½ è½å¤§æ¦ä¼°è®¡å°ä½ çHashMapéè¦åå¤å°æ°æ®ï¼å¯ä»¥å¨newçæ¶åä¼å
¶æå®åå§å®¹éï¼é¿å
æ©å®¹æä½
// é»è®¤çå è½½å å为0.75ï¼è¿æ¯ä¸ä¸ªç©ºé´åæ¶é´çä¸ä¸ªå¥½ç平衡ç¹ã妿å è½½å åè¿å°ï¼å¦0.1ï¼è¿æ ·ä¼å¯¼è´åªæ1/10çindexè¢«ä½¿ç¨æ¶å°±ä¼æ©å®¹ï¼ä¹å°±æ¯9/10çç´¢å¼ä½ä¼ç空ï¼è¿æ ·ä¼æµªè´¹ç©ºé´ï¼ä½æ¯ä½ çNode(æ¯ä¸ªkey,valueä¼å
è£
æNodeåå¨å¨ableä¸)å°±ä¸å®¹æéå¤åºç°å¨æä¸ªç´¢å¼ä½ä¸
// 妿å è½½å åè¿å¤§ï¼æ¯å¦è®¾ç½®ä¸º10ï¼è¿æ ·ä¼å¯¼è´ä½ æä¸ªç´¢å¼ä½ä¸ä¼åºç°å¤ä¸ªNodeï¼è·åNodeæ¶å°±ä¼é æå¤æ¬¡æ¯è¾ãæ¯å¦åå§å®¹é为16ï¼å è½½å å为10ï¼ å°±ä¼åºç°160个Nodeåæ¾å¨å¨16个索å¼ä½ç½®ä¸ï¼å¹³åæ¯ä¸ªé½æ10个Nodeï¼get(key)æ¶å°±ä¼åæ¯è¾å
ç´ çkeyï¼èä¸è½ç´æ¥éè¿hashå¼ååºå
ç´
final float loadFactor;
// 使ç¨keyçhashCodeçææ°çhashå¼ï¼å 为hashCodeæ¹æ³å¯ä»¥è¢«ä»»æéåï¼ä¸ºäºé¿å
æä¸å¥½çhashCode()å®ç°ï¼æä»¥éè¦å°hashCodeéæ°hashï¼
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
/**
* Associates the specified value with the specified key in this map.
* If the map previously contained a mapping for the key, the old
* value is replaced.
*
* @param key key with which the specified value is to be associated
* @param value value to be associated with the specified key
* @return the previous value associated with key, or
* null if there was no mapping for key.
* (A null return can also indicate that the map
* previously associated null with key.)
*/
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
/**
* Implements Map.put and related methods
*
* @param hash hash for key
* @param key the key
* @param value the value to put
* @param onlyIfAbsent if true, don't change existing value
* @param evict if false, the table is in creation mode.
* @return previous value, or null if none
*/
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node[] tab; Node p; int n, i;
tab = table;
n = tab.lenght;
// 1. é¦å
æ¥çtableæ¯å¦ä¸ºç©º(tableæ¯åå¨èç¹çæ°ç»)
if (tab == null || n == 0){
n = (tab = resize()).length;
}
// éè¿ä½ä¸æä½è·å该hashå¼å¯¹åºçindexï¼ä½ä¸è¿ç®ä¿è¯ç»æè¯å®å°äº(length-1)
int index = (n-1) & hash;
p = tab[index]; //åå¾è¯¥ç´¢å¼ä½ç½®ä¸ç第ä¸ä¸ªèç¹(æ°ç»ç´¢å¼åªè½åå°ç¬¬ä¸ä¸ªNodeï¼(å¦æè¿æ)åç»çNodeåªè½éè¿Nodeçnext屿§ä¾æ¬¡è®¿é®)
if (p == null) { // å¦æè¯¥ä½ç½®ä¸çå
ç´ ä¸ºç©ºï¼å说æä¹å没æä»»ä½å
ç´ æ¾å
¥å°è¯¥ä½ç½®ä¸ï¼è¯¥å
ç´ (p)ä½ä¸ºè¯¥ä½ç½®ä¸ç第ä¸ä¸ªnode
tab[index] = newNode(hash, key, value, null);
} else { // ä¸ä¸ºç©ºï¼è¯´æä¹åå·²ç»æå
ç´ åå
¥è¯¥ç´¢å¼ä½ç½®ï¼(å³ä¸¤ä¸ªå
ç´ çhashå¼ä¸length-1çä½ä¸è¿è¡å¾å°åä¸ä¸ªindexå¼)
Node e; K k;
// 夿ï¼å½åçKeyçhashå¼åä¹åçååºçç¸åä½ç½®ä¸ç第ä¸ä¸ªèç¹pçhashå¼ç¸çï¼ä¸ä»ä»¬çkey乿¯ç¸åçï¼å¦æä¸ºtrueï¼å表示Keyæ¯åä¸ä¸ªå¯¹è±¡
if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))) {
e = p; // Key对象已åå¨ï¼æ¡ä»¶æç«ï¼å°åæ¥çNodeæ¥å¾
èµå¼ç»e,åç»ä¼å¯¹eè¿è¡å¤æã
} else if (p instanceof TreeNode) { // ç¨äºTreeMapçå
ç´ å¤æ?? TODO
e = ((TreeNode)p).putTreeVal(this, tab, hash, key, value);
} else {
// éå该索å¼ä½ç½®ä¸çNodeé¾è¡¨ï¼for循ç¯ä¸æ²¡æéåºæ¡ä»¶ï¼ä¸é¢çæ¡ä»¶æ»¡è¶³æ¶ä¼ä¸»å¨breakï¼
// éååªä¼åºç°ä»¥ä¸ä¸¤ç§æ
åµä¸çä¸ç§ï¼å³è¦ä¹å·²åå¨ä¸ä¸ªkeyä¸å½åkey对象ç¸çï¼æ¤æ¶ç¨æ°çvalueæ¿æ¢åæ¥çvalueï¼
// è¦ä¹æ²¡æä»»ä½keyä¸å½åkey对象ç¸çï¼åå°æ°çkey对象æ¾å
¥è¯¥é¾è¡¨çæåä¸ä¸ªNode
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) { // 夿p.nextæ¯å¦ä¸ºç©º
// å¦æä¸ºç©ºï¼è¯´ææ²¡æNodeéè¦ç»§ç»é忝è¾ï¼èµ°å°æ¤æ¥ï¼è¯´ææ²¡æéå¤çKey被æ¾å°ã
p.next = newNode(hash, key, value, null);
if (binCount >= TREEIFY_THRESHOLD - 1) { // -1 for 1st
treeifyBin(tab, hash);
}
break; // å°æ°çé®å¼å¯¹æ¾å°p.nextä¹åç´æ¥è·³åºå¾ªç¯
}
//ã夿p.nextçkey对象æ¯å¦ä¸ºå½åçkey对象ï¼å¦ææ¯ï¼ç´æ¥è·³åºå¾ªç¯ï¼åé¢çifä¼ä¸ºåæ¥çNodeèµäºæ°çvalueå¼
if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) {
break;
}
p = e; // æ§è¡å°æ¤å¤ï¼è¯´æåé¢çæ¡ä»¶é½ä¸ºfalseï¼å°eèµå¼ç»p(ä¹å°±æ¯p=p.next)ï¼ç¶åç»§ç»æ§è¡ä¸ä¸æ¬¡for循ç¯ã
}
}
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value; // å°æ°çvalueèµå¼ç»å·²åå¨çNode
afterNodeAccess(e); // ç¨äºTreeMapï¼HashMapå¾è¯¥æ¹æ³ä¸ºç©ºå®ç°ã
return oldValue; // ç´æ¥è¿ååå§çvalueï¼ ä¸éè¦æ§è¡åé¢çæä½ï¼å ä¸ºåªæ¯æ¿æ¢äºvalueå¼ï¼ç»ææ²¡åï¼ä¹ä¸ç¨å¤æå¤ææ¯å¦éè¦æ©å®¹
}
}
++modCount; // æ§è¡å°æ¬¡æ°ï¼è¯´ææ²¡æå·²åå¨çkey对象ï¼éè¦æ·»å æ°çé®å¼å¯¹å°tableä¸ï¼å æ¤éè¦å¢å modCount(æä½æ¬¡æ°)
if (++size > threshold) //æ£æ¥æ°éæ¯å¦è¾¾å°éå¼
resize(); // æ©å®¹
afterNodeInsertion(evict); // for TreeMap
return null;
}
public V get(Object key) {
Node e;
return (e = getNode(hash(key), key)) == null ? null : e.value;
}
/**
* Implements Map.get and related methods
*
* @param hash hash for key
* @param key the key
* @return the node, or null if none
*/
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;
}
}
```
hashCodeåeuqalsæ¹æ³å¯¹åºHashMapæ¥è¯´æ¯é常éè¦ï¼æ·»å å
ç´ æ¶é常é½éè¦ä½¿ç¨hashCodeåequalsæ¹æ³æ¥å¤æé®å¼å¯¹çindex以忝å¦å·²åå¨å½åçkey对象ï¼hashCode妿¤éè¦ï¼å¯ä»¥åå å¦ä¸ç¯[å
³äºhashCodeçæç« ](./hashcode.md)
ä¸é¢æ¯ç¨äºæµè¯HashMapä¸çhash彿°ä»¥åè§å¯hashå叿
åµç示ä¾ä»£ç ï¼
```java
public class MapTest {
// è¯¥æ¹æ³åHashMapä¸çhashæ¹æ³å®å
¨ä¸è´ï¼åªæ¯HashMapä¸çhashæ¹æ³æ²¡æå
¬å¼åºæ¥ï¼ä¸è½ç´æ¥è°ç¨ï¼æä»¥åç
§æºç åäºä¸ä¸ªä¸æ ·çï¼ç¨äºè§å¯æ¯æ¥çæ§è¡ç»æ
public static int hash(Object key){
int tableLength = 16;
int h;
if(key == null ){
return 0;
} else {
// éè¿å¯¹è±¡çé»è®¤hashCodeå¾å°HashMapä¸çhashå¼ï¼å¹¶æ¥çindexå叿
åµ
h = key.hashCode();
out.println("h = hashCode: " + String.format("%1$32s",Integer.toBinaryString(h)).replace(' ','0'));
out.println("h/16 = hashCode>>>16: " + String.format("%1$32s",Integer.toBinaryString(h>>>16)).replace(' ','0'));
int hash = h ^ (h >>> 16);
out.println("hash = h ^ h/16: " + String.format("%1$32s",Integer.toBinaryString(hash)).replace(' ','0'));
out.println("last=length-1: " + String.format("%1$32s",Integer.toBinaryString((tableLength-1))).replace(' ','0'));
out.println("index=last&hash: " + String.format("%1$32s",Integer.toBinaryString((tableLength-1) & hash)).replace(' ','0'));
out.println("index=last&hash: " + ((tableLength-1) & hash));
out.println("tableLength: " + tableLength);
out.println("hash: " + hash);
out.println("key.toString: " + key.toString());
// 以䏿¯å°å¯¹è±¡è½¬æ¢ä¸ºStringåï¼éè¿StringçhashCodeå¾å°HashMapä¸çhashå¼ï¼åæ¥çindexçå叿
åµ
// å 为StringéåäºhashCodeæ¹æ³ï¼å¾å°çhashCode并䏿¯é»è®¤çhashCode(é»è®¤çhashCode为å
åå°å)
int stringH = key.toString().hashCode();
int stringHash = stringH ^ (stringH >>> 16);
out.println("key.toString.hashCode: " + String.format("%1$32s",Integer.toBinaryString(stringH)).replace(' ','0'));
out.println("key.toString.hashCode>>>16: " + String.format("%1$32s",Integer.toBinaryString(stringH>>>16)).replace(' ','0'));
out.println("key.toString.stringHash: " + String.format("%1$32s",Integer.toBinaryString(stringHash)).replace(' ','0'));
out.println("last=length-1: " + String.format("%1$32s",Integer.toBinaryString((tableLength-1))).replace(' ','0'));
out.println("index=last&stringHash: " + String.format("%1$32s",Integer.toBinaryString((tableLength-1) & stringHash)).replace(' ','0'));
out.println("index=last&stringHash: " + ((tableLength-1) & stringHash));
out.println("key.toString.hashCode: " + key.toString().hashCode());
out.println("key.toString.stringHash: " + stringHash );
out.println("==========================================================");
return hash;
}
//return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
public void testMap(){
MapTest mapTest1 = new MapTest();
MapTest mapTest2 = new MapTest();
MapTest mapTest3 = new MapTest();
MapTest mapTest4 = new MapTest();
MapTest mapTest5 = new MapTest();
MapTest mapTest6 = new MapTest();
MapTest mapTest7 = new MapTest();
MapTest mapTest8 = new MapTest();
out.println("mapTest1.hash:" + hash(mapTest1));
out.println("mapTest2.hash:" + hash(mapTest2));
out.println("mapTest3.hash:" + hash(mapTest3));
out.println("mapTest4.hash:" + hash(mapTest4));
out.println("mapTest5.hash:" + hash(mapTest5));
out.println("mapTest6.hash:" + hash(mapTest6));
out.println("mapTest7.hash:" + hash(mapTest7));
out.println("mapTest8.hash:" + hash(mapTest8));
Map map = new HashMap<>(4,2);
map.put(mapTest1,1);
map.put(mapTest2,1);
map.put(mapTest3,1);
map.put(mapTest4,1);
map.put(mapTest5,1);
map.put(mapTest6,1);
map.put(mapTest7,1);
map.put(mapTest8,1);
map.put(mapTest1,1); // æµè¯éå¤çkey
out.println("map.size:" + map.size());
}
public static void main(String[] args){
new MapTest().testMap();
}
}
```
æµè¯æ¶ï¼ä¿®æ¹tableLengthçå¼ï¼ä»¥æ¥çindexçä¸åå叿
åµï¼æçç»æå¦ä¸ï¼
```
h = hashCode: 00011011011011010011010110000110
h/16 = hashCode>>>16: 00000000000000000001101101101101
hash = h ^ h/16: 00011011011011010010111011101011
last=length-1: 00000000000000000000000000001000
index=last&hash: 00000000000000000000000000001000
index=last&hash: 8
tableLength: 9
hash: 460140267
key.toString: MapTest@1b6d3586
key.toString.hashCode: 00101011001110100000011001110001
key.toString.hashCode>>>16: 00000000000000000010101100111010
key.toString.stringHash: 00101011001110100010110101001011
last=length-1: 00000000000000000000000000001000
index=last&stringHash: 00000000000000000000000000001000
index=last&stringHash: 8
key.toString.hashCode: 725223025
key.toString.stringHash: 725232971
==========================================================
mapTest1.hash:460140267
h = hashCode: 01000101010101000110000101111100
h/16 = hashCode>>>16: 00000000000000000100010101010100
hash = h ^ h/16: 01000101010101000010010000101000
last=length-1: 00000000000000000000000000001000
index=last&hash: 00000000000000000000000000001000
index=last&hash: 8
tableLength: 9
hash: 1163142184
key.toString: MapTest@4554617c
key.toString.hashCode: 00010010000011010010111111111001
key.toString.hashCode>>>16: 00000000000000000001001000001101
key.toString.stringHash: 00010010000011010011110111110100
last=length-1: 00000000000000000000000000001000
index=last&stringHash: 00000000000000000000000000000000
index=last&stringHash: 0
key.toString.hashCode: 302854137
key.toString.stringHash: 302857716
==========================================================
mapTest2.hash:1163142184
h = hashCode: 01110100101000010100010010000010
h/16 = hashCode>>>16: 00000000000000000111010010100001
hash = h ^ h/16: 01110100101000010011000000100011
last=length-1: 00000000000000000000000000001000
index=last&hash: 00000000000000000000000000000000
index=last&hash: 0
tableLength: 9
hash: 1956720675
key.toString: MapTest@74a14482
key.toString.hashCode: 01011111101101001001001010011001
key.toString.hashCode>>>16: 00000000000000000101111110110100
key.toString.stringHash: 01011111101101001100110100101101
last=length-1: 00000000000000000000000000001000
index=last&stringHash: 00000000000000000000000000001000
index=last&stringHash: 8
key.toString.hashCode: 1605669529
key.toString.stringHash: 1605684525
==========================================================
mapTest3.hash:1956720675
h = hashCode: 00010101010000001110000110011101
h/16 = hashCode>>>16: 00000000000000000001010101000000
hash = h ^ h/16: 00010101010000001111010011011101
last=length-1: 00000000000000000000000000001000
index=last&hash: 00000000000000000000000000001000
index=last&hash: 8
tableLength: 9
hash: 356578525
key.toString: MapTest@1540e19d
key.toString.hashCode: 11011000100100011101000001101001
key.toString.hashCode>>>16: 00000000000000001101100010010001
key.toString.stringHash: 11011000100100010000100011111000
last=length-1: 00000000000000000000000000001000
index=last&stringHash: 00000000000000000000000000001000
index=last&stringHash: 8
key.toString.hashCode: -661532567
key.toString.stringHash: -661583624
==========================================================
mapTest4.hash:356578525
h = hashCode: 01100111011100110010011110110110
h/16 = hashCode>>>16: 00000000000000000110011101110011
hash = h ^ h/16: 01100111011100110100000011000101
last=length-1: 00000000000000000000000000001000
index=last&hash: 00000000000000000000000000000000
index=last&hash: 0
tableLength: 9
hash: 1735606469
key.toString: MapTest@677327b6
key.toString.hashCode: 01001110111101011110010000001000
key.toString.hashCode>>>16: 00000000000000000100111011110101
key.toString.stringHash: 01001110111101011010101011111101
last=length-1: 00000000000000000000000000001000
index=last&stringHash: 00000000000000000000000000001000
index=last&stringHash: 8
key.toString.hashCode: 1324737544
key.toString.stringHash: 1324722941
==========================================================
mapTest5.hash:1735606469
h = hashCode: 00000001010010101110010110100101
h/16 = hashCode>>>16: 00000000000000000000000101001010
hash = h ^ h/16: 00000001010010101110010011101111
last=length-1: 00000000000000000000000000001000
index=last&hash: 00000000000000000000000000001000
index=last&hash: 8
tableLength: 9
hash: 21685487
key.toString: MapTest@14ae5a5
key.toString.hashCode: 10011100011111100100110110110000
key.toString.hashCode>>>16: 00000000000000001001110001111110
key.toString.stringHash: 10011100011111101101000111001110
last=length-1: 00000000000000000000000000001000
index=last&stringHash: 00000000000000000000000000001000
index=last&stringHash: 8
key.toString.hashCode: -1669444176
key.toString.stringHash: -1669410354
==========================================================
mapTest6.hash:21685487
h = hashCode: 01111111001100010010010001011010
h/16 = hashCode>>>16: 00000000000000000111111100110001
hash = h ^ h/16: 01111111001100010101101101101011
last=length-1: 00000000000000000000000000001000
index=last&hash: 00000000000000000000000000001000
index=last&hash: 8
tableLength: 9
hash: 2133941099
key.toString: MapTest@7f31245a
key.toString.hashCode: 01100110001011000100111111001101
key.toString.hashCode>>>16: 00000000000000000110011000101100
key.toString.stringHash: 01100110001011000010100111100001
last=length-1: 00000000000000000000000000001000
index=last&stringHash: 00000000000000000000000000000000
index=last&stringHash: 0
key.toString.hashCode: 1714180045
key.toString.stringHash: 1714170337
==========================================================
mapTest7.hash:2133941099
h = hashCode: 01101101011011110110111000101000
h/16 = hashCode>>>16: 00000000000000000110110101101111
hash = h ^ h/16: 01101101011011110000001101000111
last=length-1: 00000000000000000000000000001000
index=last&hash: 00000000000000000000000000000000
index=last&hash: 0
tableLength: 9
hash: 1835991879
key.toString: MapTest@6d6f6e28
key.toString.hashCode: 10011100100010101001110011100101
key.toString.hashCode>>>16: 00000000000000001001110010001010
key.toString.stringHash: 10011100100010100000000001101111
last=length-1: 00000000000000000000000000001000
index=last&stringHash: 00000000000000000000000000001000
index=last&stringHash: 8
key.toString.hashCode: -1668637467
key.toString.stringHash: -1668677521
==========================================================
mapTest8.hash:1835991879
map.size:8
Process finished with exit code 0
```