HashMap是java中常用的集合类,它用于存储键值对的数据格式,搞清楚HashMap的工作原理和get()、put()方法是如何工作的是很有必要的。
jdk version:1.6.0_45
在java中定义一个HashMap:
HashMap map = new HashMap();
从源码角度分析, 定义一个HashMap调用它的构造方法HashMap():
public HashMap() {
this.loadFactor = DEFAULT_LOAD_FACTOR; // 默认加载因子0.75
threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR); // 元素满了以后扩充的大小:16×0.75=12
table = new Entry[DEFAULT_INITIAL_CAPACITY]; // 定义了一个大小为16的Entry数组
init();
}
下面是HashMap里的内部类Enrty的部分源码:
static class Entry<K,V> implements Map.Entry<K,V> {
final K key;
V value;
Entry<K,V> next; // 指向链表的下一结点
final int hash; // 根据key的hashcode计算得到
由此可见定义一个HashMap后堆内存中将会有
1.大小为16的Entry数组叫做table
2.table数组储存的是Entry类的对象,Entry类包含了key-value作为实例变量
当执行put()方法往HashMap里存数据源码如下:
public V put(K key, V value) {
if (key == null)
return putForNullKey(value); // 当key为null时没有抛出异常,所以HashMap允许key为null
int hash = hash(key.hashCode()); // 计算key的hashcode
int i = indexFor(hash, table.length); // 根据hash值和table的长度来判断存入的位置
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; // 如果key已经存在就执行更新
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(hash, key, value, i); // 添加新结点
return null;
}
由此可见,执行get()方法:
1.检查key是否为null,如果为null将存入table[0]的位置
2.计算key的hashcode,然后再执行hash方法得到最终的hash值,根据hash值和table的长度算出索引位置
3.如果key有相同的hash值,会以链表的形式进行存储,如果key相同将会替换原先的值
当执行get()方法获取特定key的value值源码如下:
public V get(Object key) {
if (key == null)
return getForNullKey();
int hash = hash(key.hashCode());
for (Entry<K,V> e = table[indexFor(hash, table.length)];
e != null;
e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
return e.value;
}
return null;
}
跟put()方法类似,执行get()方法:
1.如果key为null,返回table[0]
2.计算出key的hash值随后求出索引值
3.遍历链表,找到key相同的value值,如果没有返回null
参考:
1.http://www.importnew.com/10620.html
2.http://coderbee.net/index.php/java/20131018/519