更新:文章中“阀值”这个词是错误的,正确的是“阈值”,意思:阈值又叫临界值,是指一个效应能够产生的最低值或最高值。
*********************************************************************************
什么是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,
这里对其他三个不在讲解,实现方式一致,如果有兴趣可以去找一下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------