LinkedHashMap 与 HashMap

HashMap:

开发中用得更多的当然是HashMap,在Map中插入、删除和获取元素,HashMap是比较好的选择。它根据key的hashcode值进行数据存储,根据key可以直接获取对应的value,在效率上也是非常快的。HashMap允许一个为null的key,至于value可以有多个null。但是如果需要进行多线程的并发写HashMap,就可能造成数据的不一致情况,这个时候可以使用Collections.synchronizedMap的方式,或者使用Hashtable,或者更高级的ConcurrentHashMap,这个是jdk1.5出现的并发包下的,主要用来解决并发的Map操作。

注:ConcurrentHashMap的性能是优于Hashtable和Collections.synchronizedMap的。

LinkedHashMap:

顾名思义多了一层链表操作,既然有了链表,那必然就能找到插入数据的顺序了,也就是插入的数据,在遍历取出时,是于插入的顺序一致的,其他也具有map的特性。原因如下:

public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V>
{

    private static final long serialVersionUID = 3801124242820219131L;

    private transient Entry<K,V> header;

    private final boolean accessOrder;

    public LinkedHashMap(int initialCapacity, float loadFactor) {
        super(initialCapacity, loadFactor);
        accessOrder = false;
    }
}
它本身就是从HashMap继承而来,并且实现了Map接口,LinkedHashMap的实现基本和HashMap一致,但是他多一个header属性,这个属性就是用来额外存储顺序的。

linkedHashMap部分源码


 void init() {
        header = new Entry<>(-1, null, null, null);
        header.before = header.after = header;
    }

    @Override
    void transfer(HashMap.Entry[] newTable, boolean rehash) {
        int newCapacity = newTable.length;
        for (Entry<K,V> e = header.after; e != header; e = e.after) {
            if (rehash)
                e.hash = (e.key == null) ? 0 : hash(e.key);
            int index = indexFor(e.hash, newCapacity);
            e.next = newTable[index];
            newTable[index] = e;
        }
    }
    public boolean containsValue(Object value) {
        // Overridden to take advantage of faster iterator
        if (value==null) {
            for (Entry e = header.after; e != header; e = e.after)
                if (e.value==null)
                    return true;
        } else {
            for (Entry e = header.after; e != header; e = e.after)
                if (value.equals(e.value))
                    return true;
        }
        return false;
    }
    public V get(Object key) {
        Entry<K,V> e = (Entry<K,V>)getEntry(key);
        if (e == null)
            return null;
        e.recordAccess(this);
        return e.value;
    }

    public void clear() {
        super.clear();
        header.before = header.after = header;
    }
    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);
        }
        private void remove() {
            before.after = after;
            after.before = before;
        }
        private void addBefore(Entry<K,V> existingEntry) {
            after  = existingEntry;
            before = existingEntry.before;
            before.after = this;
            after.before = this;
        }
        void recordAccess(HashMap<K,V> m) {
            LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m;
            if (lm.accessOrder) {
                lm.modCount++;
                remove();
                addBefore(lm.header);
            }
        }

        void recordRemoval(HashMap<K,V> m) {
            remove();
        }
    }

    private abstract class LinkedHashIterator<T> implements Iterator<T> {
        Entry<K,V> nextEntry    = header.after;
        Entry<K,V> lastReturned = null;
        int expectedModCount = modCount;

        public boolean hasNext() {
            return nextEntry != header;
        }

        public void remove() {
            if (lastReturned == null)
                throw new IllegalStateException();
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();

            LinkedHashMap.this.remove(lastReturned.key);
            lastReturned = null;
            expectedModCount = modCount;
        }

        Entry<K,V> nextEntry() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
            if (nextEntry == header)
                throw new NoSuchElementException();

            Entry<K,V> e = lastReturned = nextEntry;
            nextEntry = e.after;
            return e;
        }
    }
从源码上可以看出,之所有会存在插入和取出顺序,还是由于链表的左右,before,after.

在工作中,使用得linkedHashMap更多的是为了保持与某个数组或者集合的顺序一致,同时又构建比较复杂key-value型的数据结构,此时一般就会用到这个了。

他其实与HashMap没有什么区别,不同的是他定义了一个Entry<K,V> header,这个header并没有放在table里面,而是单独出来的。

LinkedHashMap通过继承HashMap的Entry并添加了两个属性Entry<K,V> before, after和header集合起来组成一个双向链表,来实现插入顺序排序和访问顺序排序。


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值