初识LinkedHashMap
上两篇文章讲了HashMap和HashMap在多线程下激发的问题,说明白,HashMap是一种非经常见、很是有用的荟萃,而且在多线程环境下利用不妥会有线程安详问题。
大大都环境下,只要不涉及线程安详问题,Map根基都可以利用HashMap,不外HashMap有一个问题,就是迭代HashMap的顺序并不是HashMap安排的顺序,也就是无序。HashMap的这一缺点往往会带来困扰,因为有些场景,我们等候一个有序的Map。
这个时候,LinkedHashMap就闪亮登场了,它固然增加了时间和空间上的开销,可是通过维护一个运行于所有条目标双向链表,LinkedHashMap担保了元素迭代的顺序。
四个存眷点在LinkedHashMap上的谜底
LinkedHashMap根基数据布局
关于LinkedHashMap,先提两点:
1、LinkedHashMap可以认为是HashMap+LinkedList,即它既利用HashMap操纵数据布局,又利用LinkedList维护插入元素的先后顺序
2、LinkedHashMap的根基实现思想就是—-多态。可以说,领略多态,再去领略LinkedHashMap道剖析事半功倍;反之也是,对付LinkedHashMap道理的进修,也可以促进和加深对付多态的领略。
为什么可以这么说,首先看一下,LinkedHashMap的界说:
public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V> { ... }
看到,LinkedHashMap是HashMap的子类,自然LinkedHashMap也就担任了HashMap中所有非private的要领。再看一下LinkedHashMap中自己的要领:
看到LinkedHashMap中并没有什么操纵数据布局的要领,也就是说LinkedHashMap操纵数据布局(好比put一个数据),和HashMap操纵数据的要领完全一样,无非就是细节上有一些的差异而已。
LinkedHashMap和HashMap的区别在于它们的根基数据布局上,看一下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); } ... }
列一下Entry内里有的一些属性吧:
个中前面四个,也就是赤色部门是从HashMap.Entry中担任过来的;后头两个,也就是蓝色部门是LinkedHashMap独占的。不要搞错了next和before、After,next是用于维护HashMap指定table位置上毗连的Entry的顺序的,before、After是用于维护Entry插入的先后顺序的。
照旧用图暗示一下,列一部属性罢了:
初始化LinkedHashMap
如果有这么一段代码:
public static void main(String[] args) { LinkedHashMap<String, String> linkedHashMap = new LinkedHashMap<String, String>(); linkedHashMap.put("111", "111"); linkedHashMap.put("222", "222"); }
首先是第3行~第4行,new一个LinkedHashMap出来,看一下做了什么:
public LinkedHashMap() { super(); accessOrder = false; }
public HashMap() { this.loadFactor = DEFAULT_LOAD_FACTOR; threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR); table = new Entry[DEFAULT_INITIAL_CAPACITY]; init(); }
void init() { header = new Entry<K,V>(-1, null, null, null); header.before = header.after = header; }
/** * The head of the doubly linked list. */ private transient Entry<K,V> header;
这里呈现了第一个多态:init()要领。尽量init()要领界说在HashMap中,可是由于:
1、LinkedHashMap重写了init要领
2、实例化出来的是LinkedHashMap
因此实际挪用的init要领是LinkedHashMap重写的init要领。假设header的地点是0×00000000,那么初始化完毕,实际上是这样的:
LinkedHashMap添加元素