LinkedHashMap类源码解析
来源:互联网 发布:newsql数据库哪个最好 编辑:程序博客网 时间:2024/05/16 11:43
LinkedHashMap
1.通过链表实现存储,可以根据插入顺序遍历数组
2.hashcode计算方法和HashMap的一样
继承HashMap
实现Map
public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V>
成员变量
private static final long serialVersionUID = 3801124242820219131L; /** * 双链表的头结点 */ private transient Entry<K,V> header; /** * 遍历的顺序 对于访问顺序,为true;对于插入顺序,则为false(默认) * true for access-order, <tt>false</tt> for insertion-order. * * @serial */ private final boolean accessOrder;
构造函数
/** * 构造函数 * * @param initialCapacity 初始容量 * @param loadFactor 装载因子 * @throws IllegalArgumentException if the initial capacity is negative * or the load factor is nonpositive */ public LinkedHashMap(int initialCapacity, float loadFactor) { super(initialCapacity, loadFactor); accessOrder = false; } /** * 装载因子0.75的构造函数 * @param initialCapacity 初始容量 * @throws IllegalArgumentException if the initial capacity is negative */ public LinkedHashMap(int initialCapacity) { super(initialCapacity); accessOrder = false; } /** * 构造函数 *default initial capacity (16) and load factor (0.75). */ public LinkedHashMap() { super(); accessOrder = false; } /** * 构造函数:m集合元素加入到当前map中 * default load factor (0.75) * @param m the map whose mappings are to be placed in this map * @throws NullPointerException if the specified map is null */ public LinkedHashMap(Map<? extends K, ? extends V> m) { super(m); accessOrder = false; } /** * 构造函数 * @param initialCapacity the initial capacity * @param loadFactor the load factor * @param accessOrder the ordering mode - <tt>true</tt> for * access-order, <tt>false</tt> for insertion-order * @throws IllegalArgumentException if the initial capacity is negative * or the load factor is nonpositive */ public LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder) { super(initialCapacity, loadFactor); this.accessOrder = accessOrder; }
结点定义结构
/** * LinkedHashMap entry.结点定义 */ private static class Entry<K,V> extends HashMap.Entry<K,V> { // These fields comprise the doubly linked list used for iteration. Entry<K,V> before, after; Entry(int hash, K key, V value, HashMap.Entry<K,V> next) { super(hash, key, value, next); } /** * remove */ private void remove() { before.after = after; after.before = before; } /** * addBefore */ 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); } } void recordRemoval(HashMap<K,V> m) { remove(); } }
双链表的初始化
/** * 初始化,可以看出有一个头指针 */ @Override void init() { header = new Entry<>(-1, null, null, null); header.before = header.after = header; } /** * Transfers all entries to new table array. This method is called * by superclass resize. It is overridden for performance, as it is * faster to iterate using our linked list. */ @Override void transfer(HashMap.Entry[] newTable, boolean rehash) { int newCapacity = newTable.length; for (Entry<K,V> e = header.after; e != header; e = e.after) { if (rehash) e.hash = (e.key == null) ? 0 : hash(e.key); int index = indexFor(e.hash, newCapacity); e.next = newTable[index]; newTable[index] = e; } }
containsValue
直接根据双链表进行顺序遍历、
重写了HashMap的containsValue,效率提高
/** * containsValue * @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) { // Overridden to take advantage of faster iterator if (value==null) { for (Entry e = header.after; e != header; e = e.after) if (e.value==null) return true; } else { for (Entry e = header.after; e != header; e = e.after) if (value.equals(e.value)) return true; } return false; }
没有实现containsKey方法
HashMap中是根据key计算hashcode,找到对应的table[i],在顺序查找,现在这个查找效率比较高,毕竟只遍历了部分数据。
clear
/** * clear */ public void clear() { super.clear(); header.before = header.after = header; }
get
getEntry 方法是调用父类,其程序原理和containsKey方法一样,在HashMap中containsKey方法调用的getEntry方法。
/** * V get(Object key) */ public V get(Object key) { Entry<K,V> e = (Entry<K,V>)getEntry(key); if (e == null) return null; e.recordAccess(this); return e.value; }
LinkedHashMap没有实现put方法,其重写了HashMap.put里面的recordAccess、addEntry方法
HashMap.put
public V put(K key, V value) { if (table == EMPTY_TABLE) { inflateTable(threshold); } if (key == null) return putForNullKey(value); int hash = hash(key); // 计算hash值 int i = indexFor(hash, table.length); // 转化为所在数组的下标 for (Entry<K,V> e = table[i]; e != null; e = e.next) { // 顺序遍历所在链表,判断是否已经存在 Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { V oldValue = e.value; e.value = value; // key已经存在,新的value 更新老的value e.recordAccess(this); return oldValue; } } modCount++; addEntry(hash, key, value, i); // 不存在时候 插入该新的节点 return null; }
LinkedHashMap重写recordAccess、addEntry方法
/** * 重写HashMap的方法, * This override alters behavior of superclass put method. It causes newly * allocated entry to get inserted at the end of the linked list and * removes the eldest entry if appropriate. */ void addEntry(int hash, K key, V value, int bucketIndex) { super.addEntry(hash, key, value, bucketIndex); // 父类方法 // Remove eldest entry if instructed Entry<K,V> eldest = header.after; if (removeEldestEntry(eldest)) { removeEntryForKey(eldest.key); } } /** * This override differs from addEntry in that it doesn't resize the * table or remove the eldest entry. */ void createEntry(int hash, K key, V value, int bucketIndex) { HashMap.Entry<K,V> old = table[bucketIndex]; Entry<K,V> e = new Entry<>(hash, key, value, old); // 新结点 e table[bucketIndex] = e; // table 中加入结点 e e.addBefore(header); // 加入到头部 size++; } protected boolean removeEldestEntry(Map.Entry<K,V> eldest) { return false; }}
可以看出,表面上LinkedHashMap通过双链表作为存储结构,其实双链表只是记录结点的插入顺序,方便了对LinkedHashMap中结点的遍历,其父类的table同样作为存储结构,table的存在是使得相同的hashcode的结点将会存储在同一个table[i]桶内。符合Map的定义,如果没有table数组,直接双链表存储,没有必要计算hashcode,与LinkedList几乎意义一样。 table数组的存在,在get方法和containsKey方法中用到,LinkedHashMap没有重写containsKey方法,上面有讲解。
迭代器
// 根据插入顺序的迭代器 private abstract class LinkedHashIterator<T> implements Iterator<T> { Entry<K,V> nextEntry = header.after; Entry<K,V> lastReturned = null; /** * The modCount value that the iterator believes that the backing * List should have. If this expectation is violated, the iterator * has detected concurrent modification. */ int expectedModCount = modCount; public boolean hasNext() { return nextEntry != header; } public void remove() { if (lastReturned == null) throw new IllegalStateException(); if (modCount != expectedModCount) throw new ConcurrentModificationException(); LinkedHashMap.this.remove(lastReturned.key); lastReturned = null; expectedModCount = modCount; } Entry<K,V> nextEntry() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); if (nextEntry == header) throw new NoSuchElementException(); Entry<K,V> e = lastReturned = nextEntry; nextEntry = e.after; return e; } } // KeyIterator private class KeyIterator extends LinkedHashIterator<K> { public K next() { return nextEntry().getKey(); } } // ValueIterator private class ValueIterator extends LinkedHashIterator<V> { public V next() { return nextEntry().value; } } // EntryIterator private class EntryIterator extends LinkedHashIterator<Map.Entry<K,V>> { public Map.Entry<K,V> next() { return nextEntry(); } } // These Overrides alter the behavior of superclass view iterator() methods Iterator<K> newKeyIterator() { return new KeyIterator(); } Iterator<V> newValueIterator() { return new ValueIterator(); } Iterator<Map.Entry<K,V>> newEntryIterator() { return new EntryIterator(); }
- LinkedHashMap类源码解析
- LinkedHashMap 源码解析
- LinkedHashMap源码解析
- LinkedHashMap源码解析
- LinkedHashMap源码解析
- LinkedHashMap源码解析
- LinkedHashMap源码解析
- java LinkedHashMap源码解析
- Java LinkedHashMap源码解析
- LinkedHashMap源码解析
- LinkedHashMap源码解析
- LinkedHashMap源码解析
- LinkedHashMap 源码解析
- LinkedHashMap源码解析
- d.linkedhashMap源码解析(1.7)
- JDK之LinkedHashMap源码解析
- java.util.LinkedHashMap源码解析
- java 源码解析(02) LinkedHashMap
- [Android]使用RecyclerView替代ListView(一)
- TCP/IP协议中的端口
- 用户(user)和用户组(group)管理
- org.msgpack.core.MessagePacker
- JAVA之NIO按行读写大文件,完美解决中文乱码问题
- LinkedHashMap类源码解析
- Java 多态的详解
- 面试常见的基础--二份查找--binaryFind
- TCP通信(一)——同步连接
- hdu 1753 大明A+B
- 第一篇博客的自我介绍
- Web---图片验证码生成教程详解-从简单到复杂-从本地到前后台
- CListCtrl的主要事件及鼠标响应函数
- Handler实现app启动动画