面试题答案
一键面试LinkedHashMap双向链表结构组织方式
- 节点定义:
- LinkedHashMap的节点类
Entry
继承自HashMap的Node
类,在Node
基础上新增了两个字段:Entry<K,V> before
和Entry<K,V> after
,用于维护双向链表关系。 - 例如:
static class Entry<K,V> extends HashMap.Node<K,V> { Entry<K,V> before, after; Entry(int hash, K key, V value, Node<K,V> next) { super(hash, key, value, next); } }
- LinkedHashMap的节点类
- 链表维护:
- LinkedHashMap有两个特殊的节点,
head
和tail
,分别指向双向链表的头和尾。 - 当向LinkedHashMap中插入新元素时,新元素会被添加到双向链表的尾部(默认情况下,可通过构造函数改变这种行为)。例如,执行
put(K key, V value)
操作时,新创建的Entry
节点会被添加到链表尾部,并且在put
过程中会通过修改before
和after
指针来维护链表的双向性。 - 当删除元素时,会调整双向链表中相关节点的
before
和after
指针,使链表保持连续。例如,执行remove(Object key)
操作时,找到要删除的Entry
节点后,会将其前驱节点的after
指针指向其后继节点,后继节点的before
指针指向其前驱节点。
- LinkedHashMap有两个特殊的节点,
相比普通HashMap的显著特点
- 顺序性:
- LinkedHashMap可以维护插入顺序或者访问顺序。
- 插入顺序:元素按照插入到LinkedHashMap中的顺序排列。例如,依次插入元素A、B、C,那么遍历LinkedHashMap时,顺序就是A、B、C。
- 访问顺序:当设置
accessOrder
为true
时,每次访问(get
或put
已存在的键值对)一个元素,该元素会被移到双向链表的尾部。这使得最近访问的元素总是在链表尾部,而最久未访问的元素在链表头部,常用于实现LRU(最近最少使用)缓存。
- 遍历性能:
- 由于LinkedHashMap维护了双向链表结构,在遍历元素时,时间复杂度为O(n),其中n为元素个数。相比之下,普通HashMap在遍历其元素时,由于其内部基于哈希表存储,遍历顺序是不确定的,且可能由于哈希冲突等原因,遍历性能在某些情况下不如LinkedHashMap(特别是需要按照特定顺序遍历的场景)。
- 迭代器稳定性:
- LinkedHashMap的迭代器在迭代过程中具有更好的稳定性。在迭代过程中,如果不删除当前迭代的元素,不会影响迭代的顺序。而普通HashMap在迭代过程中,如果发生结构修改(如添加或删除元素),可能会抛出
ConcurrentModificationException
,且其迭代顺序不确定。
- LinkedHashMap的迭代器在迭代过程中具有更好的稳定性。在迭代过程中,如果不删除当前迭代的元素,不会影响迭代的顺序。而普通HashMap在迭代过程中,如果发生结构修改(如添加或删除元素),可能会抛出