更新:文章中“阀值”这个词是错误的,正确的是“阈值”,意思:阈值又叫临界值,是指一个效应能够产生的最低值或最高值。
*********************************************************************************
什么是HashMap ? hashMap是用什么基础数据结构实现的?HashMap是如何解决hashCode冲突的?
hashMap的基础容器是数组+链表(transient Entry[] table)。进行存储时:
程序根据key值去hashCode: int hash = hash(key.hashCode());
然后根据hashCode找到在table中的index: int i = indexFor(hash, table.length);
然后从table中取出链表(该链表是解决hash冲突的,详细了解可以看一下“链地址法”):Entry<K,V> e = table[i];
循环链表取值或者存储等
分析类先看父类和接口:由此可知道本类有什么特性和功能。
public class HashMap<K,V>
extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable
Map:他是一个Map,存储key-value类型的键值对数据
Cloneable:他可以被克隆
Serializable:他可以被序列化和反序列化
知道了特性就看一下怎么new HashMap对象的:
1、四个构造方法进行实例化。
第一个构造器: public HashMap() ;
/** * 以容量16,系数为0.75构造一个空的HashMap * Constructs an empty <tt>HashMap</tt> with the default initial capacity * (16) and the default load factor (0.75). */ //DEFAULT_LOAD_FACTOR=0.75 //DEFAULT_INITIAL_CAPACITY= 16 public HashMap() { this.loadFactor = DEFAULT_LOAD_FACTOR; // threshold:阈值,用于判断是否需要扩容,如果容量>threshold,则需要进行扩容操作 threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR); //table为一个Entry数组 ,实例化table,初始容量16。 table = new Entry[DEFAULT_INITIAL_CAPACITY]; init(); }
此处调用了 void init() ;在hashMap中并未有特殊应用,只是为子类预留其他初始化操作
/** * 该方法是为子类留用的,在hashMap初始化之后调用,在子类中覆写该方法进行一写子类的特殊操作 * Initialization hook for subclasses. This method is called * in all constructors and pseudo-constructors (clone, readObject) * after HashMap has been initialized but before any entries have * been inserted. (In the absence of this method, readObject would * require explicit knowledge of subclasses.) */ void init() { }
第二个构造器: public HashMap(int initialCapacity) ;
/** * 用指定的初始化容量(initialCapacity)和默认的系数0.75来创建一个HashMap * Constructs an empty <tt>HashMap</tt> with the specified initial * capacity and the default load factor (0.75). * * @param initialCapacity the initial capacity. * @throws IllegalArgumentException if the initial capacity is negative. */ public HashMap(int initialCapacity) { this(initialCapacity, DEFAULT_LOAD_FACTOR);//调用第三个构造器 }
第三个构造器: public HashMap(int initialCapacity, float loadFactor);
/** * 用指定的容量和系数来创建HashMap * Constructs an empty <tt>HashMap</tt> with the specified initial * capacity and load factor. * * @param initialCapacity the initial capacity * @param loadFactor the load factor * @throws IllegalArgumentException if the initial capacity is negative * or the load factor is nonpositive */ public HashMap(int initialCapacity, float loadFactor) { //容量小于0 抛出不合法参数异常 if (initialCapacity < 0) throw new IllegalArgumentException("Illegal initial capacity: " +initialCapacity); //如果初始化容量大于1<<30,则按照最大容量进行初始化 MAXIMUM_CAPACITY == 1 << 30 == 2^30 if (initialCapacity > MAXIMUM_CAPACITY) initialCapacity = MAXIMUM_CAPACITY; //如果阀值系数<=0或者Not-a-Number 抛出不合法参数异常 if (loadFactor <= 0 || Float.isNaN(loadFactor)) throw new IllegalArgumentException("Illegal load factor: " + loadFactor); // Find a power of 2 >= initialCapacity int capacity = 1; //初始化initialCapacity如果不是2^n,则取大于initialCapacity的最小2^n为初始化容量。为什么会这样????见:附录01 while (capacity < initialCapacity) // <<= 还能这样玩,长见识了!!! capacity <<= 1; //这四行和HashMap()相同 this.loadFactor = loadFactor; threshold = (int)(capacity * loadFactor); table = new Entry[capacity]; init(); }
第四个构造器: public HashMap(Map<? extends K, ? extends V> m);
/**
*构造一个新的HashMap,数据内容和指定的Map相同
*该新的HashMap的load factor 依旧是hi0.75,容量和指定的Map相同 * Constructs a new <tt>HashMap</tt> with the same mappings as the * specified <tt>Map</tt>. The <tt>HashMap</tt> is created with * default load factor (0.75) and an initial capacity sufficient to * hold the mappings in the specified <tt>Map</tt>. * * @param m the map whose mappings are to be placed in this map * @throws NullPointerException if the specified map is null */ public HashMap(Map<? extends K, ? extends V> m) { this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1, DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR); putAllForCreate(m); }
在这里程序调用了private void putAllForCreate(Map<? extends K, ? extends V> m);在这里暂时不解释,在下面会进行解释。
2、五个putXXX()方法的实现:
第一个put()方法: public V put(K key, V value) ;
/** * 把给定的K-V键值对放入map,如果map已经有关于K的映射,则把value覆盖以前的旧值 * Associates the specified value with the specified key in this map. * If the map previously contained a mapping for the key, the old * value is replaced. * * @param key key with which the specified value is to be associated * @param value value to be associated with the specified key * @return the previous value associated with <tt>key</tt>, or * <tt>null</tt> if there was no mapping for <tt>key</tt>. * (A <tt>null</tt> return can also indicate that the map * previously associated <tt>null</tt> with <tt>key</tt>.) */ public V put(K key, V value) { //如果key为null,调用putForNullKey()进行存储,由此可见 HashMap的key允许为null if (key == null) return putForNullKey(value); //根据hash算法计算hashCode int hash = hash(key.hashCode()); //根据hashCode和table.length找到key所在table数组中的下标 int i = indexFor(hash, table.length); //取出table[i]的链表头节点,循环链表判断是否有重复数据 for (Entry<K,V> e = table[i]; e != null; e = e.next) { Object k; //此处判重为什么不直接判断key值,而要同时判断hash是否相同?既然已经找到table[i],只需要在链表中判断key是否相同即可?? 标识:XX04 if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { //如果有重复则覆盖原来数据 V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } //没有重复则新添加数据 modCount++; addEntry(hash, key, value, i); return null; }
这里调用了: private V putForNullKey(V value);
第二个put()方法: private V putForNullKey(V value);
/** * Offloaded version :没有翻译出什么意思 * 把key为null的值放入map * Offloaded version of put for null keys */ private V putForNullKey(V value) { //HashMap是用数组+链表进行数据存储的,在这里,程序把所有key为null的value放在table[0]的链表中。 //但不等同于table[0]的链表中不会存储key!= null的数据,因为有些key值通过hashCode()计算出的数组下标有可能为0 for (Entry<K,V> e = table[0]; e != null; e = e.next) { //找到key== null的节点,跟新value值 if (e.key == null) { V oldValue = e.value; e.value = value; //这个方法没看出来是干嘛的 标识:XX01 e.recordAccess(this); return oldValue; } } //如果HashMap中没找打key为null的值,则进行插入操作 //修改次数+1 标识:XX02 modCount++; //把数据添加到table[0]位置上链表的第一个元素 addEntry(0, null, value, 0); return null; }
在private V putForNullKey(V value);中继续调用了void addEntry(int hash, K key, V value, int bucketIndex) ;
/** * 把给定的key、value、和hashCode组成的entry放入容器,如果被appropriate则需要去修改table的size * Adds a new entry with the specified key, value and hash code to * the specified bucket. It is the responsibility of this * method to resize the table if appropriate. *子类可以通过覆写这个方法去修改put方法。 * Subclass overrides this to alter the behavior of put method. */ void addEntry(int hash, K key, V value, int bucketIndex) { //取出table[bucketIndex]位置的链表节点e Entry<K,V> e = table[bucketIndex]; // 创建新的entry放在table[bucketIndex] table[bucketIndex] = new Entry<K,V>(hash, key, value, e); //如果需要调整大小则进行resize()操作 if (size++ >= threshold) //按照两倍进行扩容,依旧符合容量为偶数的标准 resize(2 * table.length); }
在void addEntry(int hash, K key, V value, int bucketIndex) 中继续调用了 void resize(int newCapacity);
/** * Rehashes the contents of this map into a new array with a * larger capacity. This method is called automatically when the * number of keys in this map reaches its threshold. * * If current capacity is MAXIMUM_CAPACITY, this method does not * resize the map, but sets threshold to Integer.MAX_VALUE. * This has the effect of preventing future calls. * * @param newCapacity the new capacity, MUST be a power of two; * must be greater than current capacity unless current * capacity is MAXIMUM_CAPACITY (in which case value * is irrelevant). */ void resize(int newCapacity) { //先保存原数据 Entry[] oldTable = table; int oldCapacity = oldTable.length; //如果table容量已经达到最大值,此时无法再继续扩容,只能提高阀值,把threshold设置为Integer.MAX_VALUE。 if (oldCapacity == MAXIMUM_CAPACITY) { threshold = Integer.MAX_VALUE; return; } //新创建一个table size=newCapacity Entry[] newTable = new Entry[newCapacity]; //把原数据复制进新table中 transfer(newTable); //更新table table = newTable; //更新threshold threshold = (int)(newCapacity * loadFactor); }
在void resize(int newCapacity);中又继续调用了void transfer(Entry[] newTable);
/** * 把entrys从当前的table转移到newTable * Transfers all entries from current table to newTable. */ void transfer(Entry[] newTable) { Entry[] src = table; int newCapacity = newTable.length; //循环复制table for (int j = 0; j < src.length; j++) { Entry<K,V> e = src[j]; if (e != null) { //取消指向链表的引用,交由gc进行处理 src[j] = null; //循环复制链表 do { Entry<K,V> next = e.next; //根据hashCode计算该该节点 在table中所处的位置 int i = indexFor(e.hash, newCapacity); e.next = newTable[i];//注意此处返回的是链表的头节点,不是一个整链表,不要理解错误(弄明白什么是链表,什么事节点以及他们的关系) newTable[i] = e;//把加入链表的节点加在table[i]中。 e = next; } while (e != null); } } }
这里的 static int indexFor(int h, int length) ;是计算该entry在table中的位置。
/** * Returns index for hash code h. */ static int indexFor(int h, int length) { //为什么这样计算呢? 标识:XX03 return h & (length-1); }
------------------------------至此第一个put()方法结束,再看第二个put()方法------------------------------------------------------
第三个put()方法: public void putAll(Map<? extends K, ? extends V> m) ;
/** * 把给定的map复制进this.map,如果给定的map中有与this.map重复的key,则this.map中的数值将会被覆盖掉 * Copies all of the mappings from the specified map to this map. * These mappings will replace any mappings that this map had for * any of the keys currently in the specified map. * * @param m mappings to be stored in this map * @throws NullPointerException if the specified map is null */ public void putAll(Map<? extends K, ? extends V> m) { int numKeysToBeAdded = m.size(); //如果m为空map则返回 if (numKeysToBeAdded == 0) return; /* * Expand the map if the map if the number of mappings to be added * is greater than or equal to threshold. This is conservative(保守的); the * obvious condition is (m.size() + size) >= threshold, but this * condition could result in a map with twice the appropriate capacity(合理的容量), * if the keys to be added overlap with the keys already in this map. * By using the conservative calculation, we subject ourself * to at most one extra resize. */ //如果addedMap的容量大于this.map的阀值则进行扩容 if (numKeysToBeAdded > threshold) { //因为 threshold = (int)(capacity * loadFactor);所以capacity= threshold/loadFactor,为什么后面需要+1? 标识:XX05 int targetCapacity = (int)(numKeysToBeAdded / loadFactor + 1); //容量最大只能取MAXIMUM_CAPACITY if (targetCapacity > MAXIMUM_CAPACITY) targetCapacity = MAXIMUM_CAPACITY; int newCapacity = table.length; //求出newCapacity while (newCapacity < targetCapacity) newCapacity <<= 1; //进行扩容操作 if (newCapacity > table.length) resize(newCapacity); } //通过迭代器进行table复制 for (Iterator<? extends Map.Entry<? extends K, ? extends V>> i = m.entrySet().iterator(); i.hasNext(); ) { Map.Entry<? extends K, ? extends V> e = i.next(); put(e.getKey(), e.getValue()); } }
第四个put(): private void putForCreate(K key, V value) ;
/** * 该方法将会被构造器调用而不是put()。不需要对容器进行大小判断和扩容操作 * 这是创建entry而不是添加entry * This method is used instead of put by constructors and * pseudoconstructors (clone, readObject). It does not resize the table, * check for comodification, etc. It calls createEntry rather than * addEntry. */ // 不解释 重复 private void putForCreate(K key, V value) { int hash = (key == null) ? 0 : hash(key.hashCode()); int i = indexFor(hash, table.length); /** * 通过key寻找以前存在的entry,在克隆和反序列化的时候不会发生, * 当map是一个有序map且 * Look for preexisting entry for key. This will never happen for * clone or deserialize. It will only happen for construction if the * input Map is a sorted map whose ordering is inconsistent w/ equals. */ for (Entry<K,V> e = table[i]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) { e.value = value; return; } } //创建一个新的entry createEntry(hash, key, value, i); }
此处调用: void createEntry(int hash, K key, V value, int bucketIndex) ;
/** * 该方法除了在一些构造器中创建新的entry之外和addEntry一样。这个版本不需要担心调整容量的问题 * Like addEntry except that this version is used when creating entries * as part of Map construction or "pseudo-construction" (cloning, * deserialization). This version needn't worry about resizing the table. * *子类通过重写该方法去修改HashMap(Map)的构造方法、clone和readObject。 *即:只有这三个方法才会调用该方法,而这三个方法是进行创建、克隆和反序列化,而不是添加新的entry,因此不必考虑容量的问题。 * Subclass overrides this to alter the behavior of HashMap(Map), * clone, and readObject. */ //操作代码不再讲解 void createEntry(int hash, K key, V value, int bucketIndex) { Entry<K,V> e = table[bucketIndex]; table[bucketIndex] = new Entry<K,V>(hash, key, value, e); size++; }
该方法的三个调用处:
第五个put()方法: private void putAllForCreate(Map<? extends K, ? extends V> m) ;
//不再解释 private void putAllForCreate(Map<? extends K, ? extends V> m) { for (Iterator<? extends Map.Entry<? extends K, ? extends V>> i = m.entrySet().iterator(); i.hasNext(); ) { Map.Entry<? extends K, ? extends V> e = i.next(); putForCreate(e.getKey(), e.getValue()); } }
putXXX()说完再看三个getXXX();
3、getXXX(),的实现。
第一个get(); final Entry<K,V> getEntry(Object key);
/** * 返回指定key在hashMap中关联的entry,如果没有包含该key则返回null * Returns the entry associated with the specified key in the * HashMap. Returns null if the HashMap contains no mapping * for the key. */ //循环 判断 返回 不讲 final Entry<K,V> getEntry(Object key) { int hash = (key == null) ? 0 : hash(key.hashCode()); //注意此for循环的使用 for (Entry<K,V> e = table[indexFor(hash, table.length)]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) return e; } return null; }
第二个get():private V getForNullKey() ;
/** * 老版本中通过get()方法寻找key为null的值,key为null的值放在tableb[0]的位置 * * Offloaded version of get() to look up null keys. Null keys map * to index 0. * 英语能力有限,无法断句,求大神翻译!!! * This null case is split out into separate methods * for the sake of performance in the two most commonly used * operations (get and put), but incorporated with conditionals in * others. */ //找到key= null的value private V getForNullKey() { for (Entry<K,V> e = table[0]; e != null; e = e.next) { if (e.key == null) return e.value; } return null; }
第三个get():public V get(Object key) ;
/** * 返回指定key在map中的value值,当map中没有该key时返回null值 * Returns the value to which the specified key is mapped, * or {@code null} if this map contains no mapping for the key. * * <p>More formally, if this map contains a mapping from a key * {@code k} to a value {@code v} such that {@code (key==null ? k==null : * key.equals(k))}, then this method returns {@code v}; otherwise * it returns {@code null}. (There can be at most one such mapping.) * * <p>A return value of {@code null} does not <i>necessarily</i> * indicate that the map contains no mapping for the key; it's also * possible that the map explicitly maps the key to {@code null}. * The {@link #containsKey containsKey} operation may be used to * distinguish these two cases. * * @see #put(Object, Object) */ //与上面类似 public V get(Object key) { if (key == null) //见上面的讲解 return getForNullKey(); int hash = hash(key.hashCode()); for (Entry<K,V> e = table[indexFor(hash, table.length)]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) return e.value; } return null; }
4、其他重要方法实现
public boolean containsKey(Object key);
/** * 如果map中有指定的key则返回true * Returns <tt>true</tt> if this map contains a mapping for the * specified key. * * @param key The key whose presence in this map is to be tested * @return <tt>true</tt> if this map contains a mapping for the specified * key. */ public boolean containsKey(Object key) { return getEntry(key) != null; }
void resize(int newCapacity)
/** * 把map中的内容改写到一个容量更大的map中去,当插入时key的数量达到阀值的时候回自动调用本方法 * Rehashes the contents of this map into a new array with a * larger capacity. This method is called automatically when the * number of keys in this map reaches its threshold. * * If current capacity is MAXIMUM_CAPACITY, this method does not * resize the map, but sets threshold to Integer.MAX_VALUE. * This has the effect of preventing future calls. * * @param newCapacity the new capacity, MUST be a power of two; * must be greater than current capacity unless current * capacity is MAXIMUM_CAPACITY (in which case value * is irrelevant). */ void resize(int newCapacity) { //先保存原数据 Entry[] oldTable = table; int oldCapacity = oldTable.length; //如果table容量已经达到最大值,此时无法再继续扩容,只能提高阀值,把threshold设置为Integer.MAX_VALUE。 if (oldCapacity == MAXIMUM_CAPACITY) { threshold = Integer.MAX_VALUE; return; } //新创建一个table size=newCapacity Entry[] newTable = new Entry[newCapacity]; //把原数据复制进新table中 transfer(newTable); //更新table table = newTable; //更新threshold threshold = (int)(newCapacity * loadFactor); }
几个removeXXX()操作:
/** * 如果存在则删除指定key的entry * Removes the mapping for the specified key from this map if present. * * @param key key whose mapping is to be removed from the map * @return the previous value associated with <tt>key</tt>, or * <tt>null</tt> if there was no mapping for <tt>key</tt>. * (A <tt>null</tt> return can also indicate that the map * previously associated <tt>null</tt> with <tt>key</tt>.) */ public V remove(Object key) { Entry<K,V> e = removeEntryForKey(key); return (e == null ? null : e.value); } /** * 删除并返回改HashMap中指定的key所关联的entry,如果hashMap不包含该key则返回null * Removes and returns the entry associated with the specified key * in the HashMap. Returns null if the HashMap contains no mapping * for this key. */ final Entry<K,V> removeEntryForKey(Object key) { int hash = (key == null) ? 0 : hash(key.hashCode());//如果key== null ,则返回0,因为key==0的数据在table[0]中存储。 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--;//HashMap.size--; //删除 if (prev == e) table[i] = next; else prev.next = next; e.recordRemoval(this); //返回 return e; } prev = e; e = next; } return e; } /** * 为EntrySet定制的方法 * Special version of remove for EntrySet. */ final Entry<K,V> removeMapping(Object o) { //类型不对肯定不在map中就不用继续查找直接返回。 if (!(o instanceof Map.Entry)) return null; //重复、不解释 Map.Entry<K,V> entry = (Map.Entry<K,V>) o; Object key = entry.getKey(); 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; //循环链表,找到target进行删除 while (e != null) { Entry<K,V> next = e.next; if (e.hash == hash && e.equals(entry)) { modCount++; size--; if (prev == e) table[i] = next; else prev.next = next; e.recordRemoval(this); return e; } prev = e; e = next; } return e; }
public void clear();清空map数据
/** * 从map中移除所有的数据 * 调用返回后map将被清空 * Removes all of the mappings from this map. * The map will be empty after this call returns. */ public void clear() { //这里也++啊!!!到底干嘛用的?????? modCount++; Entry[] tab = table; //清除引用 for (int i = 0; i < tab.length; i++) tab[i] = null; //size置0 size = 0; }
public boolean containsValue(Object value);
/** * 如果map中包含一个或者多个value则返回true * Returns <tt>true</tt> if this map maps one or more keys to the * specified value. * * @param value value whose presence in this map is to be tested * @return <tt>true</tt> if this map maps one or more keys to the * specified value */ public boolean containsValue(Object value) { if (value == null) return containsNullValue(); Entry[] tab = table; //循环table for (int i = 0; i < tab.length ; i++) //循环链表,看来此方法挺耗时的!! for (Entry e = tab[i] ; e != null ; e = e.next) if (value.equals(e.value)) return true; return false; }
private boolean containsNullValue();
/** * 特例 判断是够包括 value == null的 value * 为什么不重用 public boolean containsValue(Object value) 而不进行value== null判断呢?????? * Special-case code for containsValue with null argument */ //重复 不讲 private boolean containsNullValue() { Entry[] tab = table; for (int i = 0; i < tab.length ; i++) for (Entry e = tab[i] ; e != null ; e = e.next) if (e.value == null) return true; return false; }
public Object clone();
/** * shallow copy 克隆==浅拷贝??? 标识:XX06 * Returns a shallow copy of this <tt>HashMap</tt> instance: the keys and * values themselves are not cloned. * * @return a shallow copy of this map */ public Object clone() { HashMap<K,V> result = null; try { result = (HashMap<K,V>)super.clone(); } catch (CloneNotSupportedException e) { // assert false; } result.table = new Entry[table.length]; result.entrySet = null; result.modCount = 0; result.size = 0; result.init(); result.putAllForCreate(this); return result; }
这个方法比较特殊: void addEntry(int hash, K key, V value, int bucketIndex) ;
/** * 把给定的key、value、和hashCode组成的entry放入容器,如果被appropriate则需要去修改table的size * Adds a new entry with the specified key, value and hash code to * the specified bucket. It is the responsibility of this * method to resize the table if appropriate. *子类可以通过覆写这个方法去修改put方法。 * Subclass overrides this to alter the behavior of put method. */ void addEntry(int hash, K key, V value, int bucketIndex) { //取出table[bucketIndex]位置的链表节点e Entry<K,V> e = table[bucketIndex]; // 创建新的entry放在table[bucketIndex] table[bucketIndex] = new Entry<K,V>(hash, key, value, e); //如果需要调整大小则进行resize()操作 if (size++ >= threshold) //按照两倍进行扩容,依旧符合容量为偶数的标准 resize(2 * table.length); }
迭代器的实现: private abstract class HashIterator<E> implements Iterator<E>
HashMap中有三个XXXset,所以有三个XXXiterator+HashIterator,
![](data:image/png;base64,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)
这里对其他三个不在讲解,实现方式一致,如果有兴趣可以去找一下java迭代器的使用。
//HashMap 通过Iterator 迭代器进行迭代输出,通过此对象进行实现迭代输出 private abstract class HashIterator<E> implements Iterator<E> { Entry<K,V> next; // next entry to return 下一个将要输出的节点 int expectedModCount; // For fast-fail 用来表示map在进行迭代期间是否有其他线程对map进行操作 int index; // current slot 当前对象(entry)在table中的位置 Entry<K,V> current; // current entry 当前进行输出的节点 HashIterator() { //初始化的时候设置此两值相同,在进行next的时候进行判断,如果相同则进行操作,不相同(说明同时有其他线程对map数据进行修改。不允许)则抛出异常。 expectedModCount = modCount; if (size > 0) { // advance to first entry Entry[] t = table; //找到下一个不为null的链表的头结点 while (index < t.length && (next = t[index++]) == null) ; } } public final boolean hasNext() { return next != null; } //从table中找到下一个entry链表的头节点,此方法只是更新current和next final Entry<K,V> nextEntry() { //在迭代期间如果有其他线程对map进行数据操作操作则抛出异常。 if (modCount != expectedModCount) throw new ConcurrentModificationException(); Entry<K,V> e = next; if (e == null) throw new NoSuchElementException(); //找到下一个不为null的节点 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;//entry 置空 //从Map中删除此节点 HashMap.this.removeEntryForKey(k); //重新更新操作标识 expectedModCount = modCount; } }
--------over------