LinkedHashMap原理(jdk1.8之前)

   LinkedHashMap继承了HashMap,所以也是put和get方法,只是在方法里由于多态,会实现HashMap未实现的方法。

   LinkedHashMap多了两个自己的成员变量:Entry<K,V> header,boolean accessOrder。

   LinkedHashMap之所以循环取出是有序的,就是维护了一个双向的链表,主要就是靠header来维护的。

   accessOrder:true表示按照取出的顺序排序,false按照插入的顺序排序。初始化默认是false。

public LinkedHashMap() {
        super();
        accessOrder = false;
    }
public HashMap() {
        this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);
    }
public HashMap(int initialCapacity, float loadFactor) {
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal initial capacity: " +
                                               initialCapacity);
        if (initialCapacity > MAXIMUM_CAPACITY)
            initialCapacity = MAXIMUM_CAPACITY;
        if (loadFactor <= 0 || Float.isNaN(loadFactor))
            throw new IllegalArgumentException("Illegal load factor: " +
                                               loadFactor);

        this.loadFactor = loadFactor;
        threshold = initialCapacity;
        init();
    }

在初始化对象的时候,会调用一下init()方法:

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

在这个方法里  主要是初始化了header的数据。

put数据的时候:由于是继承的HashMap,调用的依然是HashMap的put方法:

public V put(K key, V value) {
        if (table == EMPTY_TABLE) {
            inflateTable(threshold);
        }
        if (key == null)
            return putForNullKey(value);
        int hash = hash(key);
        int i = indexFor(hash, table.length);
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }

        modCount++;
        addEntry(hash, key, value, i);
        return null;
    }

在后面我们看一下addEntry()方法:

void addEntry(int hash, K key, V value, int bucketIndex) {
        if ((size >= threshold) && (null != table[bucketIndex])) {
            resize(2 * table.length);
            hash = (null != key) ? hash(key) : 0;
            bucketIndex = indexFor(hash, table.length);
        }

        createEntry(hash, key, value, bucketIndex);
    }

然后在方法的最后调用了createEntey()方法,这个是个多态方法,我们看一下LinkedHashMap里重写的方法:

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(header),这个方法里就是维护顺序链表的方法:

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

方法解析一下:

 1.把header赋值给当前插入的接点的after节点

 2.把header的before节点赋值给当前插入的接点的before节点

 3.把当前节点赋值给当前节点的before节点的after节点

 4.把当前节点赋值给当前节点的after节点的before节点

这样就形成了一个环形链表,维护顺序。

get数据的时候:

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

可以看出来这里  除了调用了hashMap的getEntry()方法,在后面还调用了  recordAccess()方法:

void recordAccess(HashMap<K,V> m) {
            LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m;
            if (lm.accessOrder) {
                lm.modCount++;
                remove();
                addBefore(lm.header);
            }
        }

在这里外面可以看见  只有当accessOrder=true的时候进行的重新排序:按照取出时间排序。

iterator循环获取值:外面看一下iterator.next()方法:

public Map.Entry<K,V> next() { return nextEntry(); }
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;
        }

在这里把nextEntry赋值给当前返回值,把当前返回值的after节点赋值给nextEntry,以便循环获取下一个。

那如何结束当前map的循环呢?让我们看一下iterator.hasNext()方法:

public boolean hasNext() {
            return nextEntry != header;
        }
外面可以看到:只有当nextEntry!= header的时候继续循环,当nextEntry == header的时候代表当前map已经遍历结束了。


  

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值