说说Java中的LinkedHashMap

在使用HashMap时,因为其插入的顺序是随机的,而我们又想按照插入的顺序进行遍历。那我们可以使用LinkedHashMap。

今天看看LinkedHashMap的源码,看是如何HashMao的插入有序。

一、构造

public class LinkedHashMap<K,V>
    extends HashMap<K,V>

    首先它是继承与HashMap的,但要实现插入顺序,就必须记录每个节点的插入顺序,所以LinkedHashMap重写了MapEntry

static class Entry<K,V> extends HashMap.Node<K,V> {
    //before是节点的前置节点,after是节点的后继节点
    LinkedHashMap.Entry<K,V> before, after;
    Entry(int hash, K key, V value, HashMap.Node<K,V> next) {
        super(hash, key, value, next);
    }
}
    在HashMap的节点上加入了两个属性,一个是前置节点,一个后置节点,以记录节点的插入顺序。

二、查询顺序的实现

    为了保证记录插入顺序,就将每个插入的节点用链表连起来,所以LinkedHashMap维护了一个表头和一个表尾。

transient LinkedHashMap.Entry<K,V> head;

/**
 * The tail (youngest) of the doubly linked list.
 */
transient LinkedHashMap.Entry<K,V> tail;

三、插入节点

    和hashMap一样,只不过LinkedHashMap重写了newNode这个方法。

Node<K,V> newNode(int hash, K key, V value, Node<K,V> e) {
    LinkedHashMap.Entry<K,V> p =
        new LinkedHashMap.Entry<K,V>(hash, key, value, e);
    linkNodeLast(p);
    return p;
}

    那么插入节点时,LinkedHashMap到底做了什么,我们可以进入到linkNodeLast这个方法中

private void linkNodeLast(LinkedHashMap.Entry<K,V> p) {
    //将当前节点插入到链表的末尾
    LinkedHashMap.Entry<K,V> last = tail;
    tail = p;
    //如果last为空,说明集合中还没有节点,所以讲节点p设为头结点
    if (last == null)
        head = p;
    //如果last不为空,则将p置于原先last节点的后面.修改节点p的前置节点指针,修改原本last节点的后置指针
    else {
        p.before = last;
        last.after = p;
    }
}

可以看到,每次插入都将新节点加到链表的末尾,并用节点的before和after指针指向前置节点和后置节点。以此记录节点顺序。

LinkedHashMap节点的删除

void afterNodeRemoval(Node<K,V> e) { // unlink
    //找出要删除节点的前置节点b和后继节点p
    LinkedHashMap.Entry<K,V> p =
            (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
    //释放节点p的所有引用
    p.before = p.after = null;
    //如果要删除节点为头结点,则将头节点指针指向要删除节点p的后继,也就是p
    if (b == null)
        head = a;
    //如果要删除节点不为头结点,则将要删除节点p的前置节点的后继指针p.before指向要删除节点的后继节点
    else
        b.after = a;
    //如果要删除节点为尾结点,则将尾节点指针指向要删除节点p的前置,也就是b
    if (a == null)
        tail = b;
    //如果要删除节点不为尾结点,则将要删除节点p的后继节点的前置指针a.before指向要删除节点的前置节点
    else
        a.before = b;
}

因为LinkedHashMap重写了afterNodeRemoval方法,可以看出,在删除节点时,将节点从记录插入顺序的链表中删除,还是原先对应的插入顺序。

总结:

        LinkedHashMap使用两个指针记录节点的插入顺序

        LinkedHashMap继承了hashMap,所以只需将改变hashMap结构的某些方法进行重写即可。

猜你喜欢

转载自blog.csdn.net/yanghan1222/article/details/80201670