在之前的文章红黑树在HashMap中的应用中,我们分析了HashMap的实现原理以及查找,插入和删除操作的源码,这一篇我们就来看看HashMap的一个子类:LinkedHashMap。
LinkedHashMap
LinkedHashMap继承自HashMap并实现了Map接口,它的API与HashMap完全一致,用法也大致相同,同样是非线程安全的集合。我们 知道HashMap存储的节点都是HashMap.Node类型的,到了LinkedHashMap中,节点类型变成了LinkedHashMapEntry,这是Node的一 个子类,在Node类的基础上增加了before和after两个指针,用于双向链表的实现,下面代码是LinkedHashMapEntry类的定义:
/** * HashMap.Node subclass for normal LinkedHashMap entries. */ static class LinkedHashMapEntry<K,V> extends HashMap.Node<K,V> { LinkedHashMapEntry<K,V> before, after; LinkedHashMapEntry(int hash, K key, V value, Node<K,V> next) { super(hash, key, value, next); } }
由于这两个指针的存在,LinkedHashMap可以在保持HashMap存储结构不变的前提下,将持有的节点额外以双向链表的形式连接起来。这个 双向链表也是LinkedHashMap与其父类最大的不同,虽然存储方式完全相同,但是LinkedHashMap可以通过双向链表做到有序遍历,而这 个顺序取决于accessOrder这个成员变量。
首先,老规矩,一起先来看看LinkedHashMap的全局成员变量:
/** * The head (eldest) of the doubly linked list. */ transient LinkedHashMapEntry<K,V> head; //指向双向链表头结点的指针 /** * The tail (youngest) of the doubly linked list. */ transient LinkedHashMapEntry<K,V> tail; //指向双向链表尾结点的指针 /** * The iteration ordering method for this linked hash map: <tt>true</tt> * for access-order, <tt>false</tt> for insertion-order. * * @serial */ //LinkedHashMap对于双向链表节点的顺序有两层维护方式。 //第一层:按照节点插入顺序排序,先来先排 //第二层:若accessOrder变量被置位true(在构造函数中传入),则每一次对节点的访问或修改都会将该节点移动到队尾 //这样一来head指针指向的就是最久没有被访问的节点,这一个特性完全符合LRU(Least Recently Used)算法 final boolean accessOrder;
OK,成员变量不多,作用也很直观。另外值得注意的是LinkedHashMap所重写的HashMap中留下的几个钩子方法,这些方法都是在 HashMap结构发生变化或节点被访问时被调用(例如put,get,remove),而HashMap中这些都是空方法,LinkedHashMap通过重写这 些方法实现了对节点双向链表结构的维护。下面就一起来看看这几个钩子方法的实现: