首页 > 代码库 > HashMap底层代码分析

HashMap底层代码分析

public HashMap() {
this.loadFactor = DEFAULT_LOAD_FACTOR;
//this.loadFactor为加载因子,其值为默认的加载因子常量:DEFAULT_LOAD_FACTOR的值,即0.75

threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);
//阈值,当容量达到默认容量的75%时,自动扩容

table = new Entry[DEFAULT_INITIAL_CAPACITY];
//创建一个Entry数组,数组大小为默认的DEFAULT_INITIAL_CAPACITY值:16
init();
}


static class Entry<K,V> implements Map.Entry<K,V> {
//Entry是HashMap里边的一个静态内部类,内部封装了键和值

final K key;
V value;
Entry<K,V> next; //next是一个Entry<K,V>对象的引用变量
final int hash; //经过计算得出的哈希值

/**
* Creates new entry.
*/
Entry(int h, K k, V v, Entry<K,V> n) {
value = http://www.mamicode.com/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 = http://www.mamicode.com/value;
value = http://www.mamicode.com/newValue;
return oldValue;
}


//存放数据:put()方法
public V put(K key, V value) {
if (key == null)
return putForNullKey(value);
//如果传进来的是个null,就返回一个null值
int hash = hash(key.hashCode());
/*
先通过键的hashCode()方法获得一个整型值,然后通过hash(int h)这个散列函数得到一个散列码
static int hash(int h) {
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}


*/
int i = indexFor(hash, table.length);
//把散列值和数组的长度来进行运算,最终得到Entry对象要存放到数组的位置(下标)

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 = http://www.mamicode.com/e.value;
e.value = http://www.mamicode.com/value;
e.recordAccess(this);
return oldValue;
}
}

modCount++;
addEntry(hash, key, value, i); //直接存放
return null;
}

*
* hashmap调用默认构造方法会产生一个默认底层是长度为16的Entry数组,首先调用key的hasCode()方法来得到一个整数,
* int hash = hash(key.hashCode());
* 这个整数就是哈希码,然后把哈希码作为参数传递到hash()函数中来进行运算,即散列运算,得到一个int类型的散列值
* int i = indexFor(hash, table.length);
* 把散列值和数组的长度来进行运算,最终得到Entry对象要存放到数组的位置(下标)
*
* hashmap内部的结构是数组加单向链表结构,因为不同的key有可能计算出相同的散列值,根据散列值计算出来的存放到数组的下标
* 会冲突(同一个下标值),此时, 如果键相同,散列值也一样,说明是同一个对象,此时会将键所对应的旧值用新的键值覆盖掉
* 如果散列值一样,键名不一样,说明是不同的对象,此时会把键值对封装成entry对象放到那个散列值对应的下标位置处,
* 原来那个entry对象会以链表形式链接在新创建的entry对象后面
*/





void addEntry(int hash, K key, V value, int bucketIndex) {
Entry<K,V> e = table[bucketIndex];
table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
if (size++ >= threshold)
resize(2 * table.length);
}

HashMap底层代码分析