JDK1.7中的hashmap。
HashMap繼承自AbstractMap,實現了Map、Cloneable、Serializable接口。
默認初始容量爲:1<<4 即 16
最大容量爲:1<<30 即2的30次方
默認負載因子:0.75
Entry<K,V>數組。
每個Entry的屬性:
final K key;
V value;
Entry<K,V> next;
int hash;
hashmap put方法
public V put(K key, V value){
if(table == EMPTY_TABLE){
inflateTable(thresold);
}
if(key==null){
return putForNullKey(value);
}
int hash=hash(key);
int i = indexFor(hash,table.length);
for(Entry<K,V> e=table[i];e!=null;e=e.next){
Object k;
if(e.hash==hash&&((k=e.key)==key||key.equals(k))){
V oldValue=e.value;
e.value=value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(hash,key,value,i);
return null;
}
put方法流程:
(1)如果table爲空,進行初始化。
(2)如果keyt爲null,調用putForNullKey()方法
(3)獲取key的hash
(4)根據hash值獲取當前節點所在的index,使用的方式是i=hash&(table.length-1);
(5)如果table[i]的位置不爲null,對鏈表進行遍歷,找到hash和key值都相等的節點,然後覆蓋原來的value,並返回舊的value;
(6)如果對應位置爲null,或者通過遍歷找不到該節點,則modCount++並調用addEntry()。
addEntry()方法
void addEntry(int hash, K key, V value, int bucketIndex){
if((size>=threshold)&&(null!=table[bucketIndex])){
resize(2*table.length);
hash=(null!=key)?hash(key):0;
bucketIndex=indexFor(hash,table.length);
}
createEntry(hash,key,value,bucketIndex);
}
如果size已經超過了threshold並且對應位置不爲空,resizehashmap。然後重新計算hash和桶位置。並創建新的entry。在創建新節點之後,將size++;
hashmap get方法
key爲空,調用getForNullKey。不爲空,調用getEntry。通過key計算對應的桶位置,並遍歷該位置的鏈表獲取節點。、
hashmap resize()方法
void resize(int newCapacity){
Entry[] oldTable=table;
int oldCapacity=oldTable.length;
if(oldCapacity==MAXIMUM_CAPACITY){
threshold=Integer.MAX_VALUE;
return;
}
Entry[] newTable=new Entry[newCapacity];
transfer(newTable,initHashSeedAsNeeded(newCapacity));
table=newTable;
threshold=(int)Math.min(newCapacity*loadFactor,MAXIMUM_CAPACITY+1);
}
transfer方法
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){
e.hash=null==e.key?0:hash(key);
}
int i=indexFor(e.hash,newCapacity);
e.next=newTable[i];
newTable[i]=e;
e=next;
}
}
resize方法流程:
新建一個長度爲原來兩倍的數組,將原數組中的內容rehash到新的數組中,然後指向新的table。