HashMap基于哈希表的Map接口实现,其中每个元素是一个key-value对,允许使用null值和null键。内部使用单链表的方式解决hash冲突的问题,当容量不足时,它会自动增长容量。
HashMap中的部分字段:
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;//默认初始容量为16
static final int MAXIMUM_CAPACITY = 1 << 30;//最大容量为2的30次方
static final float DEFAULT_LOAD_FACTOR = 0.75f;//默认加载因子为0.75
transient Entry[] table;//入口数组,每个Entry存储一条链表的头结点
transient int size;//入口数组中已用槽的数量
transient int modCount;//被修改的次数
int threshold;//容量阀值,用于判断是否需要调整HashMap的容量(threshold = 容量 * 加载因子)
final float loadFactor;//加载因子实际大小
HashMap的几种构造函数:
/*指定初始容量initialCapacity和加载因子loadFactor的构造函数*/
public HashMap(int initialCapacity, float loadFactor) {
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal initial capacity: " +
initialCapacity);
if (initialCapacity > MAXIMUM_CAPACITY)
initialCapacity = MAXIMUM_CAPACITY;//最大初始容量不允许超过2的30次方
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal load factor: " +
loadFactor);
//初始化字段
}
/*指定初始容量initialCapacity的构造函数*/
public HashMap(int initialCapacity) {
this(initialCapacity, DEFAULT_LOAD_FACTOR);
}
/*默认构造函数*/
public HashMap() {
this.loadFactor = DEFAULT_LOAD_FACTOR;
}
/*传入一个Map作为参数的构造函数*/
public HashMap(Map<? extends K, ? extends V> m) {
this.loadFactor = DEFAULT_LOAD_FACTOR;
putMapEntries(m, false);
}
Entry入口数组:
Entry数组里的每个元素存储一个key-value对,当前key的hash值、以及指向下一个key-value对的指针next。
static class Entry<K,V> implements Map.Entry<K,V> {
final K key;
V value;
final int hash;
Entry<K,V> next;
Entry(int h, K k, V v, Entry<K,V> n) {
value = v;
next = n;
key = k;
hash = h;
}
}
HashMap中的get操作:
public V get(Object key) {
if (key == null) //如果key == null,进入table[0]所指示的链表处查找
return getForNullKey();
int hash = hash(key.hashCode()); //获取key的hash值
for (Entry<K,V> e = table[indexFor(hash, table.length)]; // 遍历指定链表找出value值
e != null;
e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
return e.value;
}
//找不到值返回null
return null;
}
/*key为null的元素存储在入口数组的第一个位置(即table[0])处所指示的链表中*/
private V getForNullKey() {
for (Entry<K,V> e = table[0]; e != null; e = e.next) {
if (e.key == null)
return e.value;
}
return null;
}
/*将hash值与入口数组的长度进行某种形式上的取模运算,返回指定下标*/
static int indexFor(int h, int length) {
return h & (length-1);
}
get方法的步骤:
代码化为:
if key == null
Entry<K, V> head = table[0];
for Each node in list
if found
return value;
end for
return null;
if key != null
int hash = key.hashCode();
int i = hash % table.length;
Entry<K, V> head= table[i];
for Each node in list
if found
return value;
end for
return null;
HashMap中的put操作:
public V put(K key, V value) {
if (key == null) //若key为null,则将key-value对加入到table[0]处
return putForNullKey(value);
int hash = hash(key.hashCode()); //获取key的hash值
int i = indexFor(hash, table.length); //将hash值与入口数组的长度进行取模运算返回指定位置下标
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))) { //若key值对应的key-value对存在,则用新value值替换掉旧value值
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
// 若key值对应的key-value对不存在,则将此key-value对保存至入口数组中
modCount++;
// 将key-value对添加到table[i]处
addEntry(hash, key, value, i);
return null;
}
/*putForNullKey()的作用是将key为null的key-value对添加到table[0]位置*/
private V putForNullKey(V value) {
for (Entry<K,V> e = table[0]; e != null; e = e.next) {
if (e.key == null) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
// 如果没有存在key为null的键值对,则直接添加到table[0]处
modCount++;
addEntry(0, null, value, 0);
return null;
}
/*addEntry()的作用是新增一个Entry元素。将key-value对插入指定位置,bucketIndex是位置索引*/
void addEntry(int hash, K key, V value, int bucketIndex) {
// 头插法插入新Entry元素
Entry<K,V> e = table[bucketIndex];
table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
// 若HashMap的实际大小大于或等于阀值,则重新调整HashMap的大小
if (size++ >= threshold)
resize(2 * table.length);
}
/*resize()的作用是重新调整HashMap的大小,newCapacity是调整后的单位*/
void resize(int newCapacity) {
Entry[] oldTable = table;
int oldCapacity = oldTable.length;
if (oldCapacity == MAXIMUM_CAPACITY) {
threshold = Integer.MAX_VALUE;
return;
}
// 新建一个HashMap,将"旧HashMap"的全部元素添加到"新HashMap"中,
// 然后,将"新HashMap"赋值给"旧HashMap"。
Entry[] newTable = new Entry[newCapacity];
transfer(newTable);
table = newTable;
threshold = (int)(newCapacity * loadFactor);
}
/*将HashMap中的全部元素都转移到newTable中*/
void transfer(Entry[] newTable) {
Entry[] src = table;
int newCapacity = newTable.length;
for (int j = 0; j < src.length; j++) {
Entry<K,V> e = src[j];
if (e != null) {
src[j] = null;
do {
Entry<K,V> next = e.next;
int i = indexFor(e.hash, newCapacity);
e.next = newTable[i];
newTable[i] = e;
e = next;
} while (e != null);
}
}
}
put方法的步骤:
参考自:http://blog.csdn.net/ns_code/article/details/36034955