HashMap解读
在面试的过程中,面试官经常会向面试者提问关于HashMap的问题,今天我将在这篇文章中仔细介绍一下HashMap.
jdk7中的HashMap
介绍一下HashMap及其put和set方法实现
HashMap是由数组加上链表的数据结构书写的,它使用key-value键值对形式存储数据,每一个键值对也叫做Entry。这些个键值对(Entry)分散存储在一个数组当中,这个数组就是HashMap的主干。HashMap数组每一个元素的初始值都是Null。
下面是几个比较重要的参数
//数组的默认长度,16
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;
//默认的加载因子0.75
static final float DEFAULT_LOAD_FACTOR = 0.75f;
//数组的最大长度 2的30次方(1073741824)
static final int MAXIMUM_CAPACITY = 1 << 30;
static final Entry[] EMPTY_TABLE = {};
//table'用来存放数据的位置
transient Entry<K,V>[] table = (Entry<K,V>[]) EMPTY_TABLE;
// 存放的键值对的数量大小,Entry的数量
transient int size;
//桶(bucket)的大小,可在初始化时显式指定
int threshold;
//加载因子,可在初始化时显式指定。
final float loadFactor;
//修改的次数,用于fail-fast机制
transient int modCount;
这个数组的默认长度为16,默认加载因子为0.75,数组里面的每一个值初始化的时候默认为null.当桶中总的键值对(Entry)的数量达到capacity
* loadFactor
的大小时,数组就会扩容,第一次扩容发生在数组中Entry数量为16*0.75f=12时.每次扩容都会使得数组的容量变为原来的两倍.这两个参数在创建HashMap对象的时候都可以指定,但我们一般不指定.
对于HashMap我们最常用的两个方法就是put和get
put
jdk7中的源码如下
public V put(K key, V value) {
//如果此时的table仍旧为初始化时的EMPTY_TABLE(空数组)的话,就对其进行初始化扩容
if (table == EMPTY_TABLE) {
inflateTable(threshold);
}
//如果想要存放的数据的key值为空的话,那么就调用putForNullKey方法.
//putForNullKey会覆盖掉原先的null值对应的Entry的value(如果存在的话)
if (key == null)
return putForNullKey(value);
//对于非空的key存取方法如下
//1.计算hash值
int hash = hash(key);
//2.计算该hash值在table中的位置
int i = indexFor(hash, table.length);
//3.判断此位置中是否有Entry存在,使用equals方法判断新插入的键是否等于原有的键,
//相同的话就覆盖原有Entry的值,不同的话就插入链表的最上方
//并使新插入Entry指向原先的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 = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
//如果前面return的话,也就不会来到这里调用addEntry方法了
addEntry(hash, key, value, i);
return null;