addbefore方法如何在LinkedHashMap中工作

时间:2017-08-01 14:38:49

标签: java linkedhashmap

我正在查看LinkedHashMap的源代码,而addBefore方法让我很困惑:

private void addBefore(Entry<K,V> existingEntry) {
            after  = existingEntry;
            before = existingEntry.before;
            before.after = this;
            after.before = this;
}

在createEntry方法中调用此方法:

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++;
}

很明显,传入addBefore方法的参数始终是标题条目,因此addBefore方法中的变量始终是标题条目。此外,标头节点永远不会更改。

我的问题是addBefore方法如何工作以形成双向链表?

1 个答案:

答案 0 :(得分:2)

如果您注意到,LinkedHashMap中的每个条目都有两个指针,之前和之后。

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);
    }
}

我会逐行:

HashMap.Entry<K,V> old = table[bucketIndex];
Entry<K,V> e = new Entry<>(hash, key, value, old);
table[bucketIndex] = e;

这三行只是在hashmap中找到 bucketindex 的第一个条目,并在该存储桶列表的开头添加新节点。所以这里传递的旧参数基本上成为插入节点的下一个指针。

第4行调用addBefore方法,其中标头作为引用传递。

after = existingEntry→这里的existingEntry是标题,后面基本上是 this.after ,因此它有效地使新节点的指针指向标题。

before = existingEntry.before;→这又使得新节点的before指针指向之前的标题,这是列表中的最后一个元素(它是一个循环的双向链表)。

before.after = this;→这使得列表中最后一个节点的后指针(因为在新节点之前指向列表中的最后一个节点)指向我们正在插入的新节点。

after.before = this;→现在更改标题的before指针。之前的标题必须更改,因为列表中的最后一个节点现在是我们正在插入的新节点,并且此语句有效地执行了此操作。

因此,linkedhashmap维护一个循环双向链表,用于维护插入顺序/访问顺序(由accessOrder参数控制)。我希望这会帮助你。