Java7/8集合框架——HashMap
Posted wpbxin
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java7/8集合框架——HashMap相关的知识,希望对你有一定的参考价值。
java.util.HashMap
Java7/8中HashMap(和 ConcurrentHashMap)的相关基本操作源码介绍,这里可以直接参考【Java7/8 中的 HashMap 和 ConcurrentHashMap 全解析】,介绍得还是挺详细的,就不班门弄斧了。
关于Java7的HashMap,这里主要提几点,具体的分析还是请参考上面给的链接,
- Java7中HashMap源码的大方向就是:数组 + 单向链表(数组的元素,Entry 实例,包含四个属性:key, value, hash 值和用于单向链表的 next),对于hash冲突的元素,使用链表进行存储,每次存储在链表头,操作也比较快。
- capacity:当前数组容量,默认值是16,始终保持 2^n,可以扩容,扩容后数组大小为当前的 2 倍。
- loadFactor:负载因子,默认为 0.75。
- threshold:扩容的阈值,等于 capacity * loadFactor,当元素实际个数size大于等于threshold时,进行扩容。
Java8的HashMap,最大的改变,是使用了数组+链表+红黑树。当链表中的元素达到了 8 个时,会将链表转换为红黑树,在这些位置进行查找的时候可以由原来的耗时O(N),降低时间复杂度为 O(logN)。
关于红黑树和ConcurrentHashMap,有待后续的进一步研究。
另外还要提到的是,关于HashMap中的一些扩展点。
1、init()方法:在LinkedHashMap,该方法用于进行虚结点的初始化。
/** * 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 * HashMap中的方法 */ public HashMap(int initialCapacity, float loadFactor) { if (initialCapacity < 0) throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity); if (initialCapacity > MAXIMUM_CAPACITY) initialCapacity = MAXIMUM_CAPACITY; if (loadFactor <= 0 || Float.isNaN(loadFactor)) throw new IllegalArgumentException("Illegal load factor: " + loadFactor); this.loadFactor = loadFactor; threshold = initialCapacity; init(); } /** * Called by superclass constructors and pseudoconstructors (clone, * readObject) before any entries are inserted into the map. Initializes * the chain. * LinkHashMap中重写之后的方法 */ @Override void init() { header = new Entry<>(-1, null, null, null); header.before = header.after = header; }
2、Entry的recordAccess方法:HashMap中是空实现,从名字可以看出“记录访问”,在LinkedHashMap中进行了重写,用于根据插入或者访问元素的顺序来调整链表元素。
/** * This method is invoked whenever the value in an entry is * overwritten by an invocation of put(k,v) for a key k that‘s already * in the HashMap. * HashMap中Entry的方法 */ void recordAccess(HashMap<K,V> m) { } // 以下的是LinkedHashMap中Entry的方法 /** * Removes this entry from the linked list. */ private void remove() { before.after = after; after.before = before; } /** * Inserts this entry before the specified existing entry in the list. */ private void addBefore(Entry<K,V> existingEntry) { after = existingEntry; before = existingEntry.before; before.after = this; after.before = this; } /** * This method is invoked by the superclass whenever the value * of a pre-existing entry is read by Map.get or modified by Map.set. * If the enclosing Map is access-ordered, it moves the entry * to the end of the list; otherwise, it does nothing. */ void recordAccess(HashMap<K,V> m) { LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m; if (lm.accessOrder) { lm.modCount++; remove(); addBefore(lm.header); } }
另外还有几个点,如get(Object key)、addEntry(int hash, K key, V value, int bucketIndex)、createEntry(int hash, K key, V value, int bucketIndex)等,在LinkedHashMap中都进行了重写,用于支持根据插入或者访问元素的顺序来调整链表元素,LinkedHashMap相关的控制变量源码如下,这里大致说明下操作的顺序:
- 所有的插入元素的操作都是调用:put(K key, V value)
- 如果key已经存在,表明需要更改对应的value,此时不会增加元素,更改value时,都会调用Entry.recordAccess方法
- recordAccess中,会根据accessOrder调整访问的元素,当accessOrder = true时,表示按照访问顺序调整,把刚才访问到的元素挪到链表最后,若accessOrder = false,则按照插入元素的顺序,由于不涉及到插入元素,因此不进行操作
- 如果key不存在,则都会调用addEntry方法,这个时候,元素都是在链表最后,因此不用进行额外的操作。
- addEntry中还调用了removeEldestEntry,用于判断是否要移除最后访问或者插入的元素。这个是实现LRU的一个点。
相关具体说明后续在介绍LinkedHashMap时会进一步细讲。
/** * The iteration ordering method for this linked hash map: <tt>true</tt> * for access-order, <tt>false</tt> for insertion-order. * * @serial */ private final boolean accessOrder; //true表示按照访问顺序,默认false表示按照插入顺序,调整特定元素至尾部
以上是关于Java7/8集合框架——HashMap的主要内容,如果未能解决你的问题,请参考以下文章
Java7/8 HashMap ConcurrentHashMap
Java7/8中的HashMap和ConcurrentHashMap全解析
Java7/8 中的 HashMap 和 ConcurrentHashMap 全解析
Java并发指南13:Java7/8 中的 HashMap 和 ConcurrentHashMap 全解析