源碼
package com.collection.Map;
import java.util.Set;
public interface Map<K,V> {
interface Entry<K,V> {
K getKey();
V getValue();
V setValue(V v);
boolean equals(Object o);
int hashCode();
}
int size();
boolean isEmpty();
V put(K k,V v);
V get(K k);
V remove(Object k);
Set<Map.Entry<K, V>> entrySet();
boolean containsKey(Object k);
boolean containsValue(Object v);
}
package com.collection.Map;
import java.io.Serializable;
import java.util.AbstractSet;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Set;
public class HashMap<K, V>
implements Map<K,V>, Cloneable, Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private static final int DEFAULT_INITIAL_CAPACITY = 16; //hashMap 初始容量
private static final float DEFAULT_LOAD_FACTOR = 0.75f; //默認--加載因子
static final int MAXIMUM_CAPACITY = 1 << 30;// 最大容量爲2的30次方
int threshold;//容量的0.75倍 超過它 以2倍擴容方式擴容
//final float loadFactor;
transient Entry<K,V>[] table;
final float loadFactor;//加載因子
transient int modCount;//HashMap被改變的次數
transient int size;//寬度
private transient Set<com.collection.Map.Map.Entry<K, V>> entrySet = null;
public Set<com.collection.Map.Map.Entry<K, V>> entrySet() {
// TODO Auto-generated method stub
return entrySet0();
}
private Set<com.collection.Map.Map.Entry<K, V>> entrySet0() {
Set<com.collection.Map.Map.Entry<K, V>> es = entrySet;
return es != null ? es : (entrySet = new EntrySet());
}
private final class EntrySet extends AbstractSet<com.collection.Map.Map.Entry<K, V>>
{
@SuppressWarnings("unchecked")
public Iterator<com.collection.Map.Map.Entry<K, V>> iterator() {
return newEntryIterator();
}
@Override
public int size() {
// TODO Auto-generated method stub
return size;
}
}
private abstract class HashIterator<E> implements Iterator<E> {
Entry<K,V> next; // next entry to return
int expectedModCount; // For fast-fail
int index; // current slot
Entry<K,V> current; // current entry
HashIterator() {
expectedModCount = modCount;
if (size > 0) { // advance to first entry
Entry[] t = table;
while (index < t.length && (next = t[index++]) == null)
;
}
}
public final boolean hasNext() {
return next != null;
}
final Entry<K,V> nextEntry() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
Entry<K,V> e = next;
if (e == null)
throw new NoSuchElementException();
if ((next = e.next) == null) {
Entry[] t = table;
while (index < t.length && (next = t[index++]) == null)
;
}
current = e;
return e;
}
}
public HashMap() {
// 設置“加載因子”爲默認加載因子0.75
this.loadFactor = DEFAULT_LOAD_FACTOR;
// 設置“HashMap閾值”,當HashMap中存儲數據的數量達到threshold時,就需要將HashMap的容量加倍。
threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);
// 創建Entry數組,用來保存數據
table = new Entry[DEFAULT_INITIAL_CAPACITY];
}
public com.collection.Map.HashMap.EntryIterator newEntryIterator() {
// TODO Auto-generated method stub
return new EntryIterator();
}
private final class EntryIterator extends HashIterator<Map.Entry<K,V>> {
public Map.Entry<K,V> next() {
return nextEntry();
}
@Override
public void remove() {
// TODO Auto-generated method stub
}
}
public int hash(Object k) {
int h;
return (k==null)?0:(h=k.hashCode())^(h>>>16);
}
int indexFor(int hash, int newLength) {
// TODO Auto-generated method stub
return hash&(newLength-1);
}
static class Entry<K,V> implements Map.Entry<K, V>
{
final K k;
V v;
Entry<K,V> next;
int hash;
public Entry(int h, K k, V v, Entry<K,V> n) {
this.k = k;
this.v = v;
this.next = n;
this.hash = h;
}
@Override
public K getKey() {
return k;
}
@Override
public V getValue() {
return v;
}
@Override
public V setValue(V v) {
V oldValue = this.v;
this.v = v;
return oldValue;
}
}
@Override
public int size() {
// TODO Auto-generated method stub
return size;
}
@Override
public boolean isEmpty() {
// TODO Auto-generated method stub
return size==0;
}
@Override
public V remove(Object key) {
Entry<K,V> e = removeEntryForKey(key);
return e==null?null:e.v;
}
private Entry<K,V> removeEntryForKey(Object key) {
int findHash = (key==null)?0:hash(key);
int i = indexFor(findHash,table.length);
Entry<K,V> prev = table[i];
Entry<K,V> e = prev;
while (e!=null)
{
Entry<K,V> next = e.next;
Object k;
//當前對象等於刪除對象
if(e.hash==findHash&&((k=e.k)==k||key!=null&&key.equals(k)))
{
modCount++;
size--;
if(prev==e)
{
table[i] = next;
}
else
{
prev.next = next;
}
return e;
}
prev = e;
e = next;
}
return null;
}
@Override
public boolean containsKey(Object k) {
return getEntry(k)!=null;
}
private Entry<K,V> getEntry(Object key) {
int hash = (key==null)?0:hash(key);
for (Entry<K,V> e = table[indexFor(hash,table.length)];e!=null; e = e.next)
{
Object k;
if(e.hash==hash&&((k=e.k)==k||key!=null&&key.equals(k)) )
{
return e;
}
}
return null;
}
@Override
public boolean containsValue(Object v) {
if(v==null)
{
return containsNullValue(v);
}
Entry[] tab = table;
for(int i=0; i<tab.length; i++)
{
for(Entry<K,V> e = tab[i]; e!=null; e= e.next)
{
if(v.equals(e.v))
{
return true;
}
}
}
return false;
}
private boolean containsNullValue(Object value) {
Entry<K, V>[] tab = table;
for (int i=0; i<tab.length;i++)
{
for(Entry<K,V> e = tab[i];e!=null; e= e.next)
{
if(e.v==null)
{
return true;
}
}
}
return false;
}
@Override
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 = null;
if(e.hash==hash && ((k=e.k) == key)||(key.equals(k)) )
{
V olaValue = e.v;
e.v = value;
return olaValue;
}
}
modCount++;
addEntry(hash, key, value, i);
return null;
}
//單獨處理 鍵值爲null的
private V putForNullKey(V value) {
for (Entry<K,V> e = table[0];e!=null;e = e.next )
{
if(e.getKey()==null)
{
V oldValue = e.v;
e.v = value;
return oldValue;
}
}
modCount++;
//
addEntry(0,null,value,0);
return null;
}
private void addEntry(int h, K key, V value, int j) {
Entry<K,V> e = table[j];
//int h, K k, V v, Entry<K,V> n-----總是讓新的entry 指向 舊的entry
table[j] = new Entry<K,V>(h, key,value,e);
//threshold 超過擴充值
if(size++>threshold)
{
resize(2*table.length);
}
}
private void resize(int i) {
Entry[] oldTable = table;
int oldCapaCity = oldTable.length;
//容量 已經達到最大值
if(oldCapaCity > MAXIMUM_CAPACITY)
{
// 設置爲Integer 最大值
threshold = Integer.MAX_VALUE;
return ;
}
Entry[] newTbale = new Entry[i];
//oldtbale 舊內容copy到 newTable
transfer(newTbale);
}
private void transfer(Entry[] newTable) {
Entry[] copyFrom = table;
int newLength = newTable.length;
for (int j=0; j<table.length; j++)
{
Entry e = copyFrom[j];
if(e!=null)
{
copyFrom[j] = null;
do
{
Entry next = e.next;
// 根據新的容量計算e在新數組中的位置
int i = indexFor(e.hash, newLength);
// 將e插入到newTable[i]指向的鏈表的頭部
e.next = newTable[i];
newTable[i] = e;//給新數組賦值
//拿到下一個繼續執行程序
e = next;
}
while(e!=null);
}
}
}
public V get(Object key)
{
if(key==null)
{
return getForNullKey();
}
int hash = hash(key);
int i = indexFor(hash, table.length);
for (Entry<K,V> e = table[i]; e!=null; e = e.next )
{
Object k = null;
if(hash==e.hash&&( (k=e.k)==key) || (key.equals(k)) )
{
return e.v;
}
}
return null;
}
private V getForNullKey() {
for (Entry<K,V> e = table[0];e!=null;e = e.next)
{
if(e.k == null)
{
return e.v;
}
}
return null;
}
}
1.jdk HashMap 設計思路
以下內容是我結合了網友的資料 自己整理下
http://blog.csdn.net/lyandyhk/article/details/51147012
https://www.zhihu.com/question/20733617
1.擾動函數
以下這段代碼叫做擾動函數 jdk8有所優化
jdk 1.7
static int hash(int h) { h ^= (h >>> 20) ^ (h >>> 12); return h ^ (h >>> 7) ^ (h >>> 4); }
jdk 1.8
static int hash(int h) { int h;
return (key==null):0:(key.hashCode())^(h>>16);
}
從上面代碼看出來key.hashCode 是int類型 長度-2147483648到2147483648 顯然 這個長度數組 內存是放不下 40億
所以這個散列值不能直接拿來用,用之前還要對數組的長度取摸運算
static int indexFor(int h, int length) { return h & (length-1); }
爲什麼數組的長度要是2的整數冪? 因爲設計組成的二進制長度只有低位掩碼
(HashMap的初始大小和擴容都是以2的次方來進行的,換句話說length-1換成二進制永遠是全部爲1,
比如容量爲16,則length-1爲1111)
h中對應位取0,對應位結果爲0,h對應位取1,對應位結果爲1。這樣就有兩個結果),但是如果length-1中某一位爲0,則不論h中對應位的數字爲幾,
對應位結果都是0,這樣就讓兩個h取到同一個結果,這就是hash衝突了,恰恰length-1又是全部爲1的數,所以結果自然就將hash衝突最小化了
列如初始長度16-1
15 的二進制數00000000 00000000 00001111 假設與其他二進制數做&運算
列如下面做位運算
11110000 00000000 00001111
00000000 00000000 00001111
0111結果就是保留低四位 但是這樣做 還是有碰撞
擾動函數在這個時候 價值就體現出來
h = hashCode()
hash碼 高位16 和地低位的16 做了一個異或 以此來加大低位的隨機性
但明顯Java 8覺得擾動做一次就夠了,做4次的話,多了可能邊際效用也不大,所謂爲了效率考慮就改成一次了。
h%length與h&(length-1)得到是同一個值