jdk_Collection_HashMap源碼

源碼


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類型 長度-21474836482147483648 顯然 這個長度數組  內存是放不下 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)得到是同一個值
1.length(2的整數次冪)的特殊性導致了length-1的特殊性(二進制全爲1)
2.位運算快於十進制運算,hashmap擴容也是按位擴容,所以相比較就選擇了後者






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章