HashMap源码分析(jdk7)
- 2019 年 10 月 3 日
- 筆記
HashMap?????
? jdk1.7?HashMap????+???????????hash????????????????????????????Key???????????????1.7????????????
? ??????????????????????????????????key?????????????1.8?????????????+??+????????????????8???????????.????????????? ????jdk8??HashMap
? ?????????????????Entry???????????Entry??????(?1.8?Entry???Node??????Map.Entry)?
//hash?????Node,???Map.Entry static class Entry<K,V> implements Map.Entry<K,V> { final K key; V value; Entry<K,V> next; int hash; //Entry??????key?hash?key?value?next????? Entry(int h, K k, V v, Entry<K,V> n) { value = v; next = n; key = k; hash = h; } public final K getKey() { return key; } public final V getValue() { return value; } public final V setValue(V newValue) { V oldValue = value; value = newValue; return oldValue; } //equals?? public final boolean equals(Object o) { if (!(o instanceof Map.Entry)) return false; Map.Entry e = (Map.Entry)o; Object k1 = getKey(); Object k2 = e.getKey(); if (k1 == k2 || (k1 != null && k1.equals(k2))) { Object v1 = getValue(); Object v2 = e.getValue(); if (v1 == v2 || (v1 != null && v1.equals(v2))) return true; } return false; } //??Object?hashCode public final int hashCode() { return Objects.hashCode(getKey()) ^ Objects.hashCode(getValue()); } public final String toString() { return getKey() + "=" + getValue(); } //??put?k?v????????key???Entry?????????????????? void recordAccess(HashMap<K,V> m) { } //???????entry???????? void recordRemoval(HashMap<K,V> m) { } }
HashMap??????????
//??????????=16 static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16 //???? = 1 << 30 static final int MAXIMUM_CAPACITY = 1 << 30; //??????.??HashMap??????????HashMap??? > DEFAULT_LOAD_FACTOR * //DEFAULT_INITIAL_CAPACITY = 0.75F * 16 static final float DEFAULT_LOAD_FACTOR = 0.75f; //?????table?? static final Entry<?,?>[] EMPTY_TABLE = {}; //table[]????????EMPTY_TABLE?????????put?????resize???2????? transient Entry<K,V>[] table = (Entry<K,V>[]) EMPTY_TABLE; //map???????? != table.length transient int size; //??????size??????????resize?? //?????threshold=capacity*loadFactor int threshold; //hashTable????? final float loadFactor; /** * The number of times this HashMap has been structurally modified * Structural modifications are those that change the number of mappings in * the HashMap or otherwise modify its internal structure (e.g., * rehash). This field is used to make iterators on Collection-views of * the HashMap fail-fast. (See ConcurrentModificationException). */ transient int modCount; //hashSeed????key?hash????key?hashCode???????? //hashSeed?????????????????hash?? //???0????????? transient int hashSeed = 0;
HashMap?????
? ????HashMap????????????????
//(1)?????? //??????table?????????DEFAULT_INITIAL_CAPACITY=16??????DEFAULT_LOAD_FACTOR=0.75F public HashMap() { this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR); }
//(2)??????????? //??????table??????????????initialCapacity??????DEFAULT_LOAD_FACTOR=0.75F public HashMap(int initialCapacity) { this(initialCapacity, DEFAULT_LOAD_FACTOR); }
//(3)???????????????? //??????table???????????initialCapacity??????loadFactor public HashMap(int initialCapacity, float loadFactor) { //????????????????<0????? if (initialCapacity < 0) throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity); //??initialCapacity???????????=MAXIMUM_CAPACITY if (initialCapacity > MAXIMUM_CAPACITY) initialCapacity = MAXIMUM_CAPACITY; //???????????????? if (loadFactor <= 0 || Float.isNaN(loadFactor)) //<0????Float?????????? throw new IllegalArgumentException("Illegal load factor: " + loadFactor); //????????????map??????? this.loadFactor = loadFactor; threshold = initialCapacity; //init???????????????????????????? init(); }
? ?????3?????????????????????????????table????????????????threshold????????????(???????????????????????)???put???????????jdk8????????????.
//(4)?????map???? //??????map?????????????????map??????????+1????????? public HashMap(Map<? extends K, ? extends V> m) { //???map.size()/0.75+1 ? 16???????? this(Math.max( (int) (m.size() / DEFAULT_LOAD_FACTOR) + 1, DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR); inflateTable(threshold); //????map??????????????HashMap? putAllForCreate(m); }
? ?????????put?????inflateTable????????????????????table??????putAllForCreate?????map?????????????????????????threshold????????????????????????
(1)inflateTable????
? ?????????????????????????????????????????????????????put???????????table?????
private void inflateTable(int toSize) { //?????number????2???????MAXIMUM_CAPACITY,??jdk8?????tabSizeFor??? int capacity = roundUpToPowerOf2(toSize); //??????(??*????)?(????+1)?????? threshold = (int) Math.min(capacity * loadFactor, MAXIMUM_CAPACITY + 1); //??table?? table = new Entry[capacity]; initHashSeedAsNeeded(capacity); }
(2)roundUpToPowerOf????
private static int roundUpToPowerOf2(int number) { //number >= 0??????? //(1)number >= ???????????? //(2)0 =< number <= 1???1 //(3)1 < number < ????? return number >= MAXIMUM_CAPACITY ? MAXIMUM_CAPACITY : (number > 1) ? Integer.highestOneBit((number - 1) << 1) : 1; } //????jdk8??tabSizeFor??????? public static int highestOneBit(int i) { //?????i>0,??i?????0?????>>???????>>>????0? //?????????i=5=0101 i |= (i >> 1); //?1?i>>1=0010??2?i= 0101 | 0010 = 0111 i |= (i >> 2); //?1?i>>2=0011??2?i= 0111 | 0011 = 0111 i |= (i >> 4); //?1?i>>4=0000??2?i= 0111 | 0000 = 0111 i |= (i >> 8); //?1?i>>8=0000??2?i= 0111 | 0000 = 0111 i |= (i >> 16); //?1?i>>16=0000??2?i= 0111 | 0000 = 0111 return i - (i >>> 1); //?1?0111>>>1=0011?2?0111-0011=0100=4 //??????4? //?????roundUpToPowerOf2????????highestOneBit?????? << 1 ??????????4<<1=8.??????number???2?? }
(3)putAllForCreate????
? ??????????map????????????map???????????????????
private void putAllForCreate(Map<? extends K, ? extends V> m) { //??????????map???????????map????putForCreate????? for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) putForCreate(e.getKey(), e.getValue()); }
? putForCreate??????
private void putForCreate(K key, V value) { //??key???null????null?????hash?0????????????hash()????hash? int hash = null == key ? 0 : hash(key); //?????????hash????table?????? int i = indexFor(hash, table.length); for (Entry<K,V> e = table[i]; e != null; e = e.next) { Object k; //hash???key??????????????? if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) { e.value = value; return; } } //????????????key????????key???????????????????? createEntry(hash, key, value, i); }
(4)createEntry????
void createEntry(int hash, K key, V value, int bucketIndex) { //??????????????????key?????????????????????????? //bucket??????? Entry<K,V> e = table[bucketIndex]; /*Entry(int h, K k, V v, Entry<K,V> n) {value = v;next = n;key = k;hash = h;}*/ table[bucketIndex] = new Entry<>(hash, key, value, e);//Entry??????????????????????? size++;//???hash??????1 }
HashMap???????????
? 1.7????hash?????1.8??????????hash???????put???????get?????remove??????????indexFor?????????????????
(1)hash??
final int hash(Object k) { int h = hashSeed; //???0???0????key?String?????stringHash32??hash?? if (0 != h && k instanceof String) { return sun.misc.Hashing.stringHash32((String) k); } //????????key?hashCode???????????hashCode?????????????hash?????? //???????????????????????????????????????????????????? //??????????? h ^= k.hashCode(); h ^= (h >>> 20) ^ (h >>> 12); return h ^ (h >>> 7) ^ (h >>> 4); }
? ??????????????key?hashCode???????????????????map?put??Key-Value??Key???“fsmly”???????????????????????hashcode???????“0000_0000_0011_0110_0100_0100_1001_0010”?????map???table?????16??????index????10???15???????32??“00000000000000000000000000001111”???????????????????????28?????????????????0???????????0????????put?Entry????????key?hashCode?????????????????????????
? ??map?????????????????????????????????hashCode??????????????JDK7??????????????????????????????????.???????????????hashCode???????????hash????
? ???????????????key?hash????????indexFor?????table????????????????????hash??length-1?????????2^n????????????????????????16?len-1=15,?????1111????????????????????????hashCode????????????????????????????????????????????hash????????Java?????hash????????????????hash()????
(2)indexFor??
static int indexFor(int h, int length) { //????hash & (n - 1)?????? return h & (length-1); }
??????????key?hash??map?????length-1??????????put?Entry?table?????????????????hash????????????????????
HashMap?put????
(1)put??
public V put(K key, V value) { //????Hash Map????????????(???map?)????table??????????? //?????????????????????????map??????put?????table?{}? //????????????table????? if (table == EMPTY_TABLE) { //??inflateTable????table??????table????? //???threshold????2???????MAXIMUM_CAPACITY inflateTable(threshold); } //??key?null?????????null?K-V??????putForNullKey?? if (key == null) return putForNullKey(value); //??put???key?hash? int hash = hash(key); //??hash??table?????????? int i = indexFor(hash, table.length); //???????indexFor(hash, table.length)????1.7???????hash??????? //????????????????????i?????????????hash????? for (Entry<K,V> e = table[i]; e != null; e = e.next) { Object k; //hash????key?????????oldValue?value if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { V oldValue = e.value; e.value = value; //?????????? e.recordAccess(this); return oldValue; } } //??key????????????????key????????????table[i]????? //??modCount???????????????? modCount++; //???????key????????????? addEntry(hash, key, value, i); return null; }
(2)putForNullKey????
? ???????key?null?????????key?null??????table[0]?????????????????table[0]?head????????????????key?null???????????????value???????????????????table[0]????
//??table???key?null???Entry???????value???? private V putForNullKey(V value) { //?table[0]???? for (Entry<K,V> e = table[0]; e != null; e = e.next) { //key?null if (e.key == null) { //?value????????value V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; //???? } } modCount++; //?????0????????????? addEntry(0, null, value, 0); return null; }
(3)addEntry????
? addEntry??????????????size????????????????????????????????????????????table??????????????
/* hashmap??????????????????????????????????????????????????????????????????.??????????????????????????????????????O(1)???????????????????????????????????????????????????????. */ void addEntry(int hash, K key, V value, int bucketIndex) { //??????? //?size?????? //?????????table??????null if ((size >= threshold) && (null != table[bucketIndex])) { //???????????? resize(2 * table.length); //?????????? //????null?key?hash???null??0 hash = (null != key) ? hash(key) : 0; //??hash???? bucketIndex = indexFor(hash, table.length); } //?????????????????????????????Entry?? createEntry(hash, key, value, bucketIndex); }
(4)??put???????
- ????????????????inflateTable????.
- ????key???null???null???putForNullKey????put.??????HashMap??key?null??????table????0??
- ??hash()????key????????????hash??????????&??????????
- ???????????????key?hash???key?hash???key?equals??true??????? value
- ?????????????????????
HashMap?resize????
(1)resize?????
void resize(int newCapacity) { //??map???table?????? Entry[] oldTable = table; //???table????????? int oldCapacity = oldTable.length; //???table???????????????????????? if (oldCapacity == MAXIMUM_CAPACITY) { threshold = Integer.MAX_VALUE; return; } //?????????????????????????? Entry[] newTable = new Entry[newCapacity]; //??transfer transfer(newTable, initHashSeedAsNeeded(newCapacity)); //table?????? table = newTable; //???? threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1); }
(2)transfer????
? transfer?????????Entry?????????????????????????
void transfer(Entry[] newTable, boolean rehash) { //?????? int newCapacity = newTable.length; //????? for (Entry<K,V> e : table) { while(null != e) { Entry<K,V> next = e.next; if (rehash) { //????hash? e.hash = null == e.key ? 0 : hash(e.key); } //??????????hash????indexFor???????? int i = indexFor(e.hash, newCapacity); //?????????????????a->b->c;women //?1?????????????????e.next=null;newTable[i]=e;e=e.next //?2??????????????????e.next=head;newTable[i]=e??????????????????????;e=e.next //?3???????????????????????????????????????????????????? e.next = newTable[i]; newTable[i] = e; e = next; } } }
? ?????????????????hash?????????table??????????????????????????????table????4??????entry1->entry2->entry3,????????????????4??????????????
(3)resize??????
- ? ????????????????2???????????????????
- ??transfer???entry???table??????????????????
- ?table????table?????
HashMap?get????
//get?????????getEntry???????null?????entry?value public V get(Object key) { if (key == null) return getForNullKey(); Entry<K,V> entry = getEntry(key); return null == entry ? null : entry.getValue(); }
? ?????get??????getEntry???Entry???????Entry?value????????getEntry?????
getEntry??
//??getEntry??? final Entry<K,V> getEntry(Object key) { //????????null if (size == 0) { return null; } //?????key???hash??????? int hash = (key == null) ? 0 : hash(key); //???????????????????Entry for (Entry<K,V> e = table[indexFor(hash, table.length)]; e != null; e = e.next) { Object k; //hash???key????? if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) return e; } return null; }
getForNullKey??
//?????????key?null? private V getForNullKey() { if (size == 0) { return null; } //???table????0????????????key?null?????? for (Entry<K,V> e = table[0]; e != null; e = e.next) { //key?null????????value if (e.key == null) return e.value; } return null; }
jdk7?????????
? (1)???put???key?null????putForNullKey?????????HashMap??null??Key
? (2)???table??????????key?hashcode???hash()??????hash????length-1??&???length-1???????1??????????????????????2???????
? (3)???get??put??resize?????????key?hashcode??hash?????????hashcode????????HashMap????????(?String??)??Key.
? (4)HashMap?????????????????????????????????????????????????ConcurrentHashMap????????????????????
? (5)???????HashMap??????????
? (6)HashMap??????16??????8???????6???????????;?32???????????
jdk7?????????????
? ?????resize????????????????????resize?????????????????????????????????resize??????????
Entry<K,V> next = e.next; //??????hash?index?????... e.next = newTable[i]; newTable[i] = e; e = next;
? resize??????transfer????????????????????????????????thread1?thread2???resize???.
? (1)resize?????table???2,?????????entry4???????
? (2)????thread1???? Entry<K,V> next = e.next;?????????????????????????
? (3)??????????thread2?????thread2???transfer?????entry3?entry4???????????????????????entry1?entry2??????????????
(4)??thread1?????????entry1???????????e?Entry2????????next??Thread2??????Entry1
- ???? newTalbe[i] = e;?thread1?????e????entry1
- ???e = next????e???entry2?next????entry2?
- ???????next = e.next???next=entry2.next=entry1??thread2?????????next???entry1
?????
? (5)thread1??????entry2??????newTable[1]??????????????e?next
?6?e.next = newTable[1] ?? entry1.next ??? entry2,????????entry2.next ?????entry1(thread2???????entry2->entry1,????thread2???????)? ???????????