您的位置:首页 > 其它

HashMap源码分析

2014-10-28 16:50 295 查看

继承关系

public class HashMap<K,V>
extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable


内部变量

/**
* The default initial capacity - MUST be a power of two.
*/
//初始化table数组大小
static final int DEFAULT_INITIAL_CAPACITY = 16;

/**
* The maximum capacity, used if a higher value is implicitly specified
* by either of the constructors with arguments.
* MUST be a power of two <= 1<<30.
*/
//table数组的最大长度,2的30次方
static final int MAXIMUM_CAPACITY = 1 << 30;

/**
* The load factor used when none specified in constructor.
*/
//table数组的扩容影响因子,默认保存的节点数量超过了 数组长度*factor 就double一下长度
static final float DEFAULT_LOAD_FACTOR = 0.75f;

/**
* The table, resized as necessary. Length MUST Always be a power of two.
*/
//HashMap实现的底层数据结构,数组
transient Entry[] table;

/**
* The number of key-value mappings contained in this map.
*/
//Map中保存的key-value节点数,用来判断数组扩容条件
transient int size;

/**
* The next size value at which to resize (capacity * load factor).
* @serial
*/
//扩容的阈值
int threshold;

/**
* The load factor for the hash table.
*
* @serial
*/
//扩容因子可以由调用者传入
final float loadFactor;

/**
* The number of times this HashMap has been structurally modified
* Structural modifications are those that change the number of mappings in
* the HashMap or otherwise modify its internal structure (e.g.,
* rehash).  This field is used to make iterators on Collection-views of
* the HashMap fail-fast.  (See ConcurrentModificationException).
*/
transient volatile int modCount;


HashMap数据存储示意图



Entry数据结构

HashMap的一个内部静态类

final K key;
V value;
//当不同的key定位到table数组中同一个索引后,需要用链表把这些冲突的entry串起来
Entry<K,V> next;

//key.hashCode经过hash算法计算而来
final int hash;


put过程

1.key如果是null,调用putForNullKey,在table[0]上的链表进行遍历:

如果key为null存在,更新value,返回旧值

如果不存在,调用addEntry,new一个Entry,key为null,hash位0,插入到table[0]上,插入到链表头部

2.key不为null,计算hash值,计算数组索引index

int hash = hash(key.hashCode());

int i = indexFor(hash, table.length);

在索引为i的table[i]指向的链表上,进行遍历,

如果key存在(key值相等,且hash值相等),更新value ;

如果key不存在,调用addEntry(hash, key, value, i);

分析addEntry方法

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);
}


上面这段代码很简单了吧,就是在头部插入新的key-value,维护链表顺序,同时,如果保存的节点数大于阈值,则进行数组扩容

扩容分析

void resize(int newCapacity) {
Entry[] oldTable = table;
int oldCapacity = oldTable.length;
//如果数组长度已经最大,将阈值改为Integer.MAX_VALUE,不做任何修改
if (oldCapacity == MAXIMUM_CAPACITY) {
threshold = Integer.MAX_VALUE;
return;
}
//创建新数组
Entry[] newTable = new Entry[newCapacity];
//将节点从老的数组中迁移到新的数组中
transfer(newTable);
table = newTable;
threshold = (int)(newCapacity * loadFactor);
}

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);
}
}
}


删除key

final Entry<K,V> removeEntryForKey(Object key) {
int hash = (key == null) ? 0 : hash(key.hashCode());
int i = indexFor(hash, table.length);
Entry<K,V> prev = table[i];
Entry<K,V> e = prev;

while (e != null) {
Entry<K,V> next = e.next;
Object k;
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k)))) {
modCount++;
size--;
if (prev == e)
table[i] = next;
else
prev.next = next;
e.recordRemoval(this);
return e;
}
prev = e;
e = next;
}

return e;
}


如果你对链表这种数据结构很熟悉的话,上面这段代码就没什么意思了
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: