深入理解HashMap
1、HashMap 是什么
HashMap是散列表,K-V键值对集合。
2、HashMap 数据结构
1) 容量,增长因子,增长阔值, hashSeed 哈希因子,在
private int threshold; // =容量 * loadFactor 增长因子 默认= 16 * 0.75 = 12 ,容量的增长,主要原因是尽量避免Hash冲突,就是为了将 Map.Entry线性分布在 Map.Entry[] talbe中,也就是尽量做到 table数组中的元素的 next 为 null;
private loat loadFactor;//增长因子,默认为0.75 ,
transient int hashSeed = 0; // 在initHashSeedAsNeeded 初始化,并用于 final int hash(Object k) 方法中,算key的哈希值
2)private transient Map.Entry[] table; 也就是HashMap,内部维护着一个 元素类型为Map.Entry的数组。但这个数组是非连续存放的比如,第1个位置,第4个位置有值,
第2个位置,第三个位置为 null。
3)Map.Entry<K,V> 结构详解
private int hash;
private K key;
private V value;
prinvate Map.Entry<K,V> next; // 这里是关键中的关键
HashMap 存放图解
3、核心方法跟踪详解
---------------------------- put(K key, V value) 源码分析 -------------------------------------------------------
1、HashMap 是什么 HashMap是散列表,K-V键值对集合。 2、HashMap 数据结构 1) 容量,增长因子,增长阔值, hashSeed 哈希因子,在 private int threshold; // =容量 * loadFactor 增长因子 默认= 16 * 0.75 = 12 ,容量的增长,主要原因是尽量避免Hash冲突,就是为了将 Map.Entry线性分布在 Map.Entry[] talbe中,也就是尽量做到 table数组中的元素的 next 为 null; private loat loadFactor;//增长因子,默认为0.75 , transient int hashSeed = 0; // 在initHashSeedAsNeeded 初始化,并用于 final int hash(Object k) 方法中,算key的哈希值 2)private transient Map.Entry[] table; 也就是HashMap,内部维护着一个 元素类型为Map.Entry的数组。但这个数组是非连续存放的比如,第1个位置,第4个位置有值, 第2个位置,第三个位置为 null。 3)Map.Entry<K,V> 结构详解 private int hash; private K key; private V value; prinvate Map.Entry<K,V> next; // 这里是关键中的关键 HashMap 存放图解 3、核心方法跟踪详解 ---------------------------- put(K key, V value) 源码分析 -------------------------------------------------------
private Set<Map.Entry<K,V>> entrySet0() { Set<Map.Entry<K,V>> es = entrySet; return es != null ? es : (entrySet = new EntrySet()); } //所以代码的关键点在与 new EntrySet();//什么是EntrySet,原来是HashMap中的一静态的内部类,该类继承AbstractSet类,本身就是一个集合。 private final class EntrySet extends AbstractSet<Map.Entry<K,V>> { public Iterator<Map.Entry<K,V>> iterator() { return newEntryIterator(); } public boolean contains(Object o) { if (!(o instanceof Map.Entry)) return false; Map.Entry<K,V> e = (Map.Entry<K,V>) o; Entry<K,V> candidate = getEntry(e.getKey()); return candidate != null && candidate.equals(e); } public boolean remove(Object o) { return removeMapping(o) != null; } public int size() { return size; } public void clear() { HashMap.this.clear(); } } private final class EntryIterator extends HashIterator<Map.Entry<K,V>> { public Map.Entry<K,V> next() { return nextEntry(); } } // 重点关注一下 HashIterator 迭代器 private abstract class HashIterator<E> implements Iterator<E> { Entry<K,V> next; // next entry to return //下一个元素,因为我们知道,HashMap内部的 Map.Entry<K,V>[] table内的元素是非连续的。所以访问下一元 // 素,不能简单的用 table[++index] 这个概念。 int expectedModCount; // For fast-fail 遍历时,HashMap结构变化的次数,如果在遍历期间 modCount发生变化,则直接报错,并结束遍历 int index; // current slot 当前位置 Entry<K,V> current; // current entry 当前元素 HashIterator() { expectedModCount = modCount; //设置开始遍历时,记录HashMap结构调整的次数 if (size > 0) { // advance to first entry // 在构造方法时,先在table数组中找到第一不为空的元素,存入next属性中。 Entry[] t = table; while (index < t.length && (next = t[index++]) == null) ; } } public final boolean hasNext() { //判断是否有下一个可迭代元素,只需要判断 next是否为空即可。 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(); // nextEntry,主要实现思路是:将next的值,赋值给当前元素,然后尝试获取下一个非空Map.Entry元 // 素,找到后,赋值给next元素 if ((next = e.next) == null) { // 这句很关键,作用,先将 要本次返回的元素 next返回【开始遍历链表了】,如果该元素的next为空, //说明该元素下面没有链表,说明该hash没有冲突,然后再遍历table数组,找到下一个非空元素。 Entry[] t = table; while (index < t.length && (next = t[index++]) == null) ; } current = e; return e; }
public void remove() { // 将迭代器 中current所存储的元素,对应的key,删除,然后将current域设置为空,并重新设置 // expectedModCount的值等于modCount,,而current的赋值操作,发送在 next方法中,故 // 故,如过在遍历过程中,想删除当前元素,it.remove()方法要在it.next()方法之后调用。 if (current == null) throw new IllegalStateException(); if (modCount != expectedModCount) throw new ConcurrentModificationException(); Object k = current.key; current = null; HashMap.this.removeEntryForKey(k); expectedModCount = modCount; } } //验收 再遍历 HashMap时,remove方法与next方法的使用 public static void main(String[] args) { // TODO Auto-generated method stub HashMap<String, String> a = new HashMap(); a.put("a", "a"); a.put("b", "b"); a.put("c", "c"); a.put("d", "d"); a.put("e", "e"); a.put("f", "f"); int i = 0; for (Iterator<Map.Entry<String, String>> it = a.entrySet().iterator(); it.hasNext();) { if(i == 2) { // 如果 修改为 i == 0,,则会抛出异常 IllegalStateException 异常。 it.remove(); } Map.Entry<String, String> entry = it.next(); System.out.println(entry.getKey() + ":" + entry.getValue()); i ++; } System.out.println(a); } -----------------------------3.2 HashMap 的遍历 public Set<Map.Entry> entrySet(); end-----------------------