java集合源码阅读笔记-HashMap
来源:互联网 发布:mac adb 导出文件 编辑:程序博客网 时间:2024/05/22 08:29
HashMap也是我们使用非常多的Collection,它是基于哈希表的 Map 接口的实现,以key-value的形式存在。在HashMap中,key-value总是会当做一个整体来处理,系统会根据hash算法来来计算key-value的存储位置,我们总是可以通过key快速地存、取value。下面通过源码学习一下(本文参考http://www.cnblogs.com/chenssy/p/3521565.html):
put方法
public V put(K key, V value) { //当key为null,调用putForNullKey方法,保存null与table第一个位置中,这是HashMap允许为null的原因 if (key == null) return putForNullKey(value); //计算key的hash值 int hash = hash(key.hashCode()); ------(1) //计算key hash 值在 table 数组中的位置 int i = indexFor(hash, table.length); ------(2) //从i出开始迭代 e,找到 key 保存的位置 for (Entry<K, V> e = table[i]; e != null; e = e.next) { Object k; //判断该条链上是否有hash值相同的(key相同) //若存在相同,则直接覆盖value,返回旧value if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { V oldValue = e.value; //旧值 = 新值 e.value = value; e.recordAccess(this); return oldValue; //返回旧值 } } //修改次数增加1 modCount++; //将key、value添加至i位置处 addEntry(hash, key, value, i); return null; }
put的流程:当我们想一个HashMap中添加一对key-value时,系统首先会计算key的hash值,然后根据hash值确认在table中存储的位置。若该位置没有元素,则直接插入。否则迭代该处元素链表并依此比较其key的hash值。如果两个hash值相等且key值相等(e.hash == hash && ((k = e.key) == key || key.equals(k))),则用新的Entry的value覆盖原来节点的value。如果两个hash值相等但key值不等 ,则将该节点插入该链表的链头。
addEntry()方法
void addEntry(int hash, K key, V value, int bucketIndex) { //获取bucketIndex处的Entry Entry<K, V> e = table[bucketIndex]; //将新创建的 Entry 放入 bucketIndex 索引处,并让新的 Entry 指向原来的 Entry table[bucketIndex] = new Entry<K, V>(hash, key, value, e); //若HashMap中元素的个数超过极限了,则容量扩大两倍 if (size++ >= threshold) resize(2 * table.length); }
get方法的实现
public V get(Object key) { // 若为null,调用getForNullKey方法返回相对应的value if (key == null) return getForNullKey(); // 根据该 key 的 hashCode 值计算它的 hash 码 int hash = hash(key.hashCode()); // 取出 table 数组中指定索引处的值 for (Entry<K, V> e = table[indexFor(hash, table.length)]; e != null; e = e.next) { Object k; //若搜索的key与查找的key相同,则返回相对应的value if (e.hash == hash && ((k = e.key) == key || key.equals(k))) return e.value; } return null; }
modCount的相关知识
modCount是干嘛的啊? 让我来为你解答。众所周知,HashMap不是线程安全的,但在某些容错能力较好的应用中,如果你不想仅仅因为1%的可能性而去承受hashTable的同步开销,HashMap使用了Fail-Fast机制来处理这个问题,你会发现modCount在源码中是这样声明的。
transient volatile int modCount;
volatile关键字声明了modCount,代表了多线程环境下访问modCount,根据JVM规范,只要modCount改变了,其他线程将读到最新的值。其实在Hashmap中modCount只是在迭代的时候起到关键作用。
private abstract class HashIterator<E> implements Iterator<E> { Entry<K,V> next; // next entry to return int expectedModCount; // For fast-fail int index; // current slot Entry<K,V> current; // current entry HashIterator() { expectedModCount = modCount; if (size > 0) { // advance to first entry Entry[] t = table; while (index < t.length && (next = t[index++]) == null) ; } } public final boolean hasNext() { return next != null; } final Entry<K,V> nextEntry() { // 这里就是关键 if (modCount != expectedModCount) throw new ConcurrentModificationException(); Entry<K,V> e = next; if (e == null) throw new NoSuchElementException(); if ((next = e.next) == null) { Entry[] t = table; while (index < t.length && (next = t[index++]) == null) ; } current = e; return e; } public void remove() { if (current == null) throw new IllegalStateException(); if (modCount != expectedModCount) throw new ConcurrentModificationException(); Object k = current.key; current = null; HashMap.this.removeEntryForKey(k); expectedModCount = modCount; } }
使用Iterator开始迭代时,会将modCount的赋值给expectedModCount,在迭代过程中,通过每次比较两者是否相等来判断HashMap是否在内部或被其它线程修改,如果modCount和expectedModCount值不一样,证明有其他线程在修改HashMap的结构,会抛出异常。所以HashMap的put、remove等操作都有modCount++的计算。
jdk8的一些拓展
//如果x是一个实现了comparable接口则返回x的class对象,反之返回nullstatic Class<?> comparableClassFor(Object x) { if (x instanceof Comparable) { //ParameterizedType表示一个参数化类型,就像Collection<String>一样 Class<?> c; Type[] ts, as; Type t; ParameterizedType p; if ((c = x.getClass()) == String.class) // bypass checks return c; if ((ts = c.getGenericInterfaces()) != null) { for (int i = 0; i < ts.length; ++i) { //getRawType()返回一个type类型多代表的类或借口,如Collection<String>会返回Collection if (((t = ts[i]) instanceof ParameterizedType) && ((p = (ParameterizedType)t).getRawType() == Comparable.class) && (as = p.getActualTypeArguments()) != null && as.length == 1 && as[0] == c) // type arg is c return c; } } } return null; }
##
0 0
- java集合源码阅读笔记-HashMap
- JAVA 集合类(java.util)源码阅读笔记------HashMap
- Java集合源码阅读之HashMap
- HashMap源码阅读笔记
- HashMap源码阅读笔记
- HashMap源码阅读笔记
- HashMap源码阅读笔记
- Java源码阅读-HashMap
- Java源码阅读-HashMap
- Java集合源码阅读笔记(1)
- java基础集合源码阅读笔记
- Java集合源码阅读笔记-LinkedList
- Java集合源码阅读笔记-HashSet
- Java集合HashMap源码
- Java集合源码----HashMap
- 【Java数据结构】Hashmap、Hashtable、ConcurrentHashMap源码阅读笔记
- Java Jdk1.8 HashMap源码阅读笔记一
- Java Jdk1.8 HashMap源码阅读笔记二
- Android 四种点击事件的方法
- C++中动态分配数组的分析
- 【bzoj4196】[NOI2015]软件包管理器
- Manycore Programming: CUDA 1
- 文章标题
- java集合源码阅读笔记-HashMap
- 等比数列求和推导及优化
- 找出数组中只出现一次的2个数(类型题总汇)
- 文章标题
- JDK的下载及安装
- 面试中的二叉树题目
- Java 读书笔记12 异常处理
- java.lang.NullPointerException的原因(空指针)
- opencv3.0+opencv_contrib附加模块编译和配置相关的问题