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; }
如果你对链表这种数据结构很熟悉的话,上面这段代码就没什么意思了
相关文章推荐
- HashMap源码分析
- HashMap源码分析
- Hash算法以及java hashmap的源码分析
- Java HashMap 源码分析
- HashMap源码分析(基于JDK1.6)
- 源码分析:HashMap
- Java HashMap源码分析
- Java concurrent Framework并发容器之ConcurrentHashMap(JDK1.5)源码分析
- 源码分析:HashMap
- Java Collections Framework之HashMap源码分析(基于JDK1.6)
- HashSet和HashMap源码实现分析
- java源码分析之LinkedHashMap
- Thinking in Java之HashMap源码分析
- HashMap源码分析
- HashMap源码分析(基于JDK1.6)
- HashMap源码分析
- 集合框架源码分析三(实现类篇ArrayList,LinkedList,HashMap)
- 【转载】HashSet与HashMap关系之源码分析
- java util包学习(9)HashMap源码分析
- Java concurrent Framework并发容器之ConcurrentHashMap(Doug Lea 非JDK版)源码分析