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已经遍历结束了。