LinkedHashMap源码

java.util.LinkedHashMap
 extends HashMap<K,V> implements Map<K,V>

LinkedHashMap可以保存元素存进map中的顺序或访问元素的顺序,LinkedHashMap维护着一个运行于所有条目的双重链接列表。此链接列表定义了迭代顺序

1.类变量&常量

    transient LinkedHashMap.Entry<K,V> head;    //双向链表的头部
    transient LinkedHashMap.Entry<K,V> tail;    //双向链表的尾部
    final boolean accessOrder;  //遍历该map时采用的方法,true代表访问顺序,false代表插入顺序
2.构造方法
    //无参构造方法,默认容量16,装载因子.75等,采用插入顺序保存
    public LinkedHashMap() {
        super();
        accessOrder = false;        
    }

    public LinkedHashMap(Map<? extends K, ? extends V> m) {
        super();
        accessOrder = false;
        putMapEntries(m, false);    //将容器中的键值对插入到map中
    }

    //有初始容量的构造方法
    public LinkedHashMap(int initialCapacity) {
        super(initialCapacity);
        accessOrder = false;
    }

    //有初始容量、装载因子的构造方法
    public LinkedHashMap(int initialCapacity, float loadFactor) {
        super(initialCapacity, loadFactor);
        accessOrder = false;
    }

    //可以通过设置accessOrder来决定遍历时的访问顺序
    public LinkedHashMap(int initialCapacity,
                         float loadFactor,
                         boolean accessOrder) {
        super(initialCapacity, loadFactor);
        this.accessOrder = accessOrder;
    }

3.内部类

1.Entry:继承自HashMap的内部类Node,且在此基础上添加了before和after,
作为LinkedHashMap的内部结点。注意Entry中也有next元素,其余before和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);
        }
    }
2.LinkedHashIterator,对LinkedHashMap进行遍历,其有三个子类,分别为
LinkedKeyIterator、LinkedValueIterator和LinkedEntryIterator,代表对
key遍历、对value遍历和对Entry遍历
    abstract class LinkedHashIterator {
        LinkedHashMap.Entry<K,V> next;
        LinkedHashMap.Entry<K,V> current;
        int expectedModCount;

        LinkedHashIterator() {
            next = head;
            expectedModCount = modCount;
            current = null;
        }

        public final boolean hasNext() {
            return next != null;
        }

        final LinkedHashMap.Entry<K,V> nextNode() {
            LinkedHashMap.Entry<K,V> e = next;
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
            if (e == null)
                throw new NoSuchElementException();
            current = e;
            next = e.after;
            return e;
        }

        public final void remove() {
            Node<K,V> p = current;
            if (p == null)
                throw new IllegalStateException();
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
            current = null;
            K key = p.key;
            removeNode(hash(key), key, null, false, false);
            expectedModCount = modCount;
        }
    }
3.LinkedValues:得到value的容器类,其iterator方法会调用LinkedValueIterator的构造方法
4.LinkedKeySet:得到keySet类,其iterator方法会调用LinkedKeyIterator的构造方法
5.LinkedEntrySet:得到Entry的Set类,其iterator方法会调用LinkedEntryIterator的构造方法
6.LinkedHashIterator:对LinkedHashMap做遍历时需要的内部类
    LinkedHashMap.Entry<K,V> next;
    LinkedHashMap.Entry<K,V> current;
    int expectedModCount;

    LinkedHashIterator() {
        next = head;
        expectedModCount = modCount;
        current = null;
    }

    public final boolean hasNext() {
        return next != null;
    }

    final LinkedHashMap.Entry<K,V> nextNode() {
        LinkedHashMap.Entry<K,V> e = next;  //从head开始
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
        if (e == null)
            throw new NoSuchElementException();
        current = e;
        next = e.after; //双向链表的下一个
        return e;
    }
7.LinkedHashIterator的三个子类,分别代表对key、value和Entry遍历
final class LinkedKeyIterator extends LinkedHashIterator
        implements Iterator<K> {
        public final K next() { return nextNode().getKey(); }
    }

    final class LinkedValueIterator extends LinkedHashIterator
        implements Iterator<V> {
        public final V next() { return nextNode().value; }
    }

    final class LinkedEntryIterator extends LinkedHashIterator
        implements Iterator<Map.Entry<K,V>> {
        public final Map.Entry<K,V> next() { return nextNode(); }
    }

4.重要函数

1.分别得到相应的LinkedEntrySet、LinkedKeySet和LinkedValues
    public Set<Map.Entry<K,V>> entrySet() {
        Set<Map.Entry<K,V>> es;
        return (es = entrySet) == null ? (entrySet = new LinkedEntrySet()) : es;
    }

    public Set<K> keySet() {
        Set<K> ks;
        return (ks = keySet) == null ? (keySet = new LinkedKeySet()) : ks;
    }

    public Collection<V> values() {
        Collection<V> vs;
        return (vs = values) == null ? (values = new LinkedValues()) : vs;
    }
2.newNode方法,重写父类的newNode方法,返回一个LinkedHashMap.Entry对象,
且将该对象链接到链表的最后。注意newNode方法的调用是在putVal方法中,
新建一个newNode类,从而在这里调用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;
    }

    //树节点也要放到链表的末尾
    TreeNode<K,V> newTreeNode(int hash, K key, V value, Node<K,V> next) {
        TreeNode<K,V> p = new TreeNode<K,V>(hash, key, value, next);
        linkNodeLast(p);
        return p;
    }

image

3.linkNodeLast方法,LinkedHashMap的核心函数,将结点放到双向链表的末尾
    private void linkNodeLast(LinkedHashMap.Entry<K,V> p) {
        LinkedHashMap.Entry<K,V> last = tail;
        tail = p;
        if (last == null)   //说明是第一个Entry
            head = p;
        else {  //构建双向链表
            p.before = last;        
            last.after = p;
        }
    }
4.LinkedHashMap的put元素后可以进行一些操作(此时已经完成双向链表的相应插入操作)

    void afterNodeInsertion(boolean evict) { // possibly remove eldest
        LinkedHashMap.Entry<K,V> first;
        if (evict && (first = head) != null && removeEldestEntry(first)) {
            K key = first.key;
            //调用HashMap的removeNode方法
            removeNode(hash(key), key, null, false, true);
        }
    }

    //允许其删除最旧的元素,在被put和putAll方法时被调用,
    //可以使添加新元素的同时删除旧元素。对于缓存的子类实现,该方法非常有用(需要覆盖)  
    protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
        return false;
    }

5.  get方法,根据key得到相应的value
    public V get(Object key) {
        Node<K,V> e;
        if ((e = getNode(hash(key), key)) == null)
            return null;
        if (accessOrder)    
            afterNodeAccess(e); //若按照访问顺序遍历,则将该节点挪到链表末尾
        return e.value;
    }

    //afterNodeAccess方法,此方法被父类多个方法调用,如putVal方法中,
    //若已有相同的key存在,则会执行该方法等
    void afterNodeAccess(Node<K,V> e) {
        LinkedHashMap.Entry<K,V> last;      
        //accessOrder=true且tail!=e,将结点e挪到链表的末尾
        if (accessOrder && (last = tail) != e) { 
            LinkedHashMap.Entry<K,V> p =
                (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
            p.after = null;
            if (b == null)
                head = a;
            else
                b.after = a;
            if (a != null)
                a.before = b;
            else
                last = b;
            if (last == null)
                head = p;
            else {
                p.before = last;
                last.after = p;
        }
        tail = p;
        ++modCount;
    }

下面的图展示了访问前和访问后的状态,假设访问的结点为结点3

image

6.表示删除节点后的相关操作,被父类的removeNode方法调用    
    void afterNodeRemoval(Node<K,V> e) { // unlink
        LinkedHashMap.Entry<K,V> p =
            (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
        p.before = p.after = null;  //将p的before和after设为null,表示p不再在链表中
        if (b == null)
            head = a;
        else
            b.after = a;
        if (a == null)
            tail = b;
        else
            a.before = b;
    }
7.containsValue是按照链表的顺序来查找value的,而不是按照桶的顺序来查找value
    public boolean containsValue(Object value) {
        for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after) {
            V v = e.value;
            if (v == value || (value != null && value.equals(v)))
                return true;
        }
        return false;
    }
8.transferLinks方法,用dst结点替换src结点
其中只考虑了beforeafter域,并没有考虑next域,next会在调用tranferLinks函数中进行设定。
    private void transferLinks(LinkedHashMap.Entry<K,V> src,
                               LinkedHashMap.Entry<K,V> dst) {
        LinkedHashMap.Entry<K,V> b = dst.before = src.before;
        LinkedHashMap.Entry<K,V> a = dst.after = src.after;
        if (b == null)
            head = dst;
        else
            b.after = dst;
        if (a == null)
            tail = dst;
        else
            a.before = dst;
    }

image

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值