java源码解读之LinkedHashMap------jdk 1.7
2017-04-12 15:45
477 查看
前面分析了HashMap的实现,我们知道其底层数据存储是一个hash表(数组+单向链表)。接下来我们看一下另一个LinkedHashMap,它是HashMap的一个子类,他在HashMap的基础上维持了一个双向链表(hash表+双向链表),在遍历的时候可以使用插入顺序(先进先出,类似于FIFO),或者是最近最少使用(LRU)的顺序。
来具体看下LinkedHashMap的实现。 1.定义
public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V>
2. 属性
//其他属性从hashmap处继承 //头结点 private transient Entry<K,V> header; //引用自网上:当accessOrder为true时表示LinkedHashMap内部节点按照访问次数排序,最老的节点也就是访问最少的节点.当 accessOrder为false时表示LinkedHashMap内部节点按照插入顺序排序,最老的节点也就是最早插入的节点,该值默认为false. private final boolean accessOrder; //其他基本一致,来看看entry是怎么重写的才能实现双向链表 private static class Entry<K,V> extends HashMap.Entry<K,V> { //属性有前后节点,实现双向链表的关键 Entry<K,V> before, after; Entry(int hash, K key, V value, HashMap.Entry<K,V> next) { //直接调用父类的构造方法 super(hash, key, value, next); } private void remove() { //例如有三个节点,第一个节点的下一个节点指向第三个节点,第三个节点的上一个节点指向第一个节点 before.after = after; after.before = before; } //把一个节点加到当前节点的前 private void addBefore(Entry<K,V> existingEntry) { //将当前节点的下一个节点指向传入节点 after = existingEntry; //把当前节点的前一个节点指向传入节点的上一个节点 before = existingEntry.before; //改变前后节点的指向为自己 before.after = this; after.before = this; } //在hashmap调用put相同key的时候,get,putForNullKey的时候调用 void recordAccess(HashMap<K,V> m) { LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m; //如果开启算法排序 if (lm.accessOrder) { //修改次数+1 lm.modCount++; //先删除再添加,进行排序 //删除当前节点 remove(); //把当前元素加入到header前 addBefore(lm.header); } } //删除当前元素 void recordRemoval(HashMap<K,V> m) { remove(); } }
3. 构造器
//自己设定临界值和负载因子 public LinkedHashMap(int initialCapacity, float loadFactor) { super(initialCapacity, loadFactor); accessOrder = false; } //自己设置临界值 public LinkedHashMap(int initialCapacity) { super(initialCapacity); accessOrder = false; } //使用默认属性 public LinkedHashMap() { super(); accessOrder = false; } //根据传入的map集合创建LinkedHashMap public LinkedHashMap(Map<? extends K, ? extends V> m) { super(m); accessOrder = false; } //自己设定临界值和负载因子,是否开启算法排序 public LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder) { super(initialCapacity, loadFactor); this.accessOrder = accessOrder; }
4. 解析部分方法源码 4.1 解析部分源码 LinkedHashMap是继承hashmap的,所以增删改查方法基本一致,只是重写了其中几个方法
void transfer(HashMap.Entry[] newTable, boolean rehash) { int newCapacity = newTable.length; //从hashmap的foreach遍历改为从头结点开始遍历 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); //把newTable[index]原来位置的结点改为当前节点e节点的下一个节点 e.next = newTable[index]; //把newTable[index]赋值为当前节点e newTable[index] = e; } } void init() { //创建LinkedHashMap前,先创建头节点 header = new Entry<>(-1, null, null, null); header.before = header.after = header; } public V get(Object key) { //如果通过key查找不到对应entry,则直接返回null Entry<K,V> e = (Entry<K,V>)getEntry(key); if (e == null) return null; //与hashmap最大的不同,如果开启了算法排序,则对entry进行排序 e.recordAccess(this); return e.value; } public void clear() { super.clear(); //LinkedHashMap与hashmap不同的清空之处在于他有一个头节点的前后关系需要清理 header.before = header.after = header; } void addEntry(int hash, K key, V value, int bucketIndex) { super.addEntry(hash, key, value, bucketIndex); //判断是否需要删除头结点,因为header不存元素,所以是header的下一个元素,默认是false Entry<K,V> eldest = header.after; if (removeEldestEntry(eldest)) { removeEntryForKey(eldest.key); } } 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); table[bucketIndex] = e; //维护节点的前后关系 e.addBefore(header); size++; }
相关文章推荐
- java源码解读之ArrayList------jdk 1.7
- java源码解读之HashSet------jdk 1.7
- java源码解读之LinkedList------jdk 1.7
- java源码解读之TreeMap------jdk 1.7
- java源码解读之HashMap------jdk 1.7
- java.util源码之AbstractCollection(基于jdk1.7)
- Java之ArrayList源码解读(JDK 1.8)
- JDK 1.7 java.io 源码学习之Closeable、Flushable、Appendable接口
- JDK源码(1.7) -- java.util.Map<K,V>
- JDK 1.7 java.io 源码学习之Serializable接口
- Java--String源码解析(JDK1.7)
- JDK 1.7 java.io 源码学习之AutoCloseable接口和try-with-resources语法
- JDK源码(1.7) -- java.util.Arrays
- Java String 源码浅析 JDK1.7
- JDK 1.7 java.io 源码学习之ObjectInputStream和ObjectOutputStream
- JDK 1.7 java.io 源码学习之ByteArrayInputStream和ByteArrayOutputStream
- JDK源码(1.7) -- java.util.AbstractCollection<E>
- JDK源码学习(4)-java.util.HashMap、LinkedHashMap与TreeMap
- Java-LinkedHashMap源码解读
- JDK源码(1.7) -- java.util.List<E>