刚入java不久的程序猿,对于简单的使用已毫不满足,最终为了一探究竟,翻开了JDK的源码,以下观点为自己的理解及看了多篇博客的总结,欢迎各位大神指出不对的地方,当然也欢迎和我一样刚学的同学,一起加油努力吧~~
LinkedHashMap是什么 |
首先看到这个名字,大家肯定会想LinkedHashMap会不会和HashMap有关系。没错,他们是有关系的, LinkedHashMap是继承了HashMap的,也就是说HashMap是LinkedHashMap的父类,那他们之间到底有什么区别呢,我这里先说下区别,下面我会通过代码来让大家看清这些区别,LinkedHashMap是有序的,但是HashMap是无序的,这里的有序指的是放入顺序,对于LinkedHashMap简单的介绍到这里,有了初步了解后,我们来看下具体的源码吧,如果没有看过HashMap的小伙伴建议先去看一下HashMap源码解析
LinkedHashMap源码解析 |
public class LinkedHashMap<K,V>
extends HashMap<K,V>
implements Map<K,V>{
...
}
刚刚上面已经说了LinkedHashMap继承了HashMap,具体代码请看HashMap源码解析,就不详细介绍了,接下来我们看一段测试的代码,了解下刚刚说的有序
package test;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map.Entry;
public class Test {
public static void main(String[] args) {
LinkedHashMap<String, String> linkedHashMap=new LinkedHashMap<>();
HashMap<String, String> hashMap=new HashMap<>();
linkedHashMap.put("1", "1");
linkedHashMap.put("2", "2");
linkedHashMap.put("3", "3");
linkedHashMap.put("4", "4");
linkedHashMap.put("5", "5");
linkedHashMap.put("6", "6");
linkedHashMap.put("7", "7");
hashMap.put("1", "1");
hashMap.put("2", "2");
hashMap.put("3", "3");
hashMap.put("4", "4");
hashMap.put("5", "5");
hashMap.put("6", "6");
hashMap.put("7", "7");
for (Entry<String, String> string : linkedHashMap.entrySet()) {
System.out.println(string);
}
System.out.println("-----------------------");
for (Entry<String, String> string : hashMap.entrySet()) {
System.out.println(string);
}
}
}
-------------------------------------------------------------------------
1=1
2=2
3=3
4=4
5=5
6=6
7=7
*************************************
3=3
2=2
1=1
7=7
6=6
5=5
4=4
上面为测试的代码和测试的结果,我们可以看到HashMap输出后之前的顺序已经打乱了,是无序的,而LinkedHashMap按照放入顺序输出,是有序的,有了基本概念后我们去探究一下源码
/**
* The head of the doubly linked list.
*/
private transient Entry<K,V> header;
/**
* LinkedHashMap排序标志,true表示按照访问排序,false表示按照插入排序
*/
private final boolean accessOrder;
/**
* 调用父类HashMap中构造方法,参数为初始化容量和加载因子
*/
public LinkedHashMap(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor);
accessOrder = false;
}
/**
* 调用父类HashMap中构造方法,参数为初始化容量,加载因子为HashMap中默认的0.75f
*/
public LinkedHashMap(int initialCapacity) {
super(initialCapacity);
accessOrder = false;
}
/**
* 调用父类HashMap中构造方法,参数为HashMap中默认的初始化容量16,加载因子0.75f
*/
public LinkedHashMap() {
super();
accessOrder = false;
}
/**
* 调用父类HashMap中构造方法,参数为map
*/
public LinkedHashMap(Map<? extends K, ? extends V> m) {
super(m);
accessOrder = false;
}
/**
* 调用父类HashMap中构造方法,参数为初始化容量,加载因子,排序方法
*/
public LinkedHashMap(int initialCapacity,
float loadFactor,
boolean accessOrder) {
super(initialCapacity, loadFactor);
this.accessOrder = accessOrder;
}
上面就是LinkedHashMap的构造方法,都是调用了父类的构造,所以只要HashMap看懂了,这个没太大难度,这里主要注意的就是调用完父类构造后,设置了一个排序方法,如未传入参数,默认为按照插入顺序排序,接下来我们继续看代码
/**
* 重写父类inti方法,初始化header
*/
@Override
void init() {
header = new Entry<>(-1, null, null, null);
header.before = header.after = header;
}
/**
* 重写父类transfer方法,父类resize方法将会调用此方法,重写该方法目的是为了提高效率
*/
@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;
}
}
/**
* 判断是否包含这个value
*/
public boolean containsValue(Object value) {
// 参数为null时,进行特殊处理
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;
}
/**
* 根据key值获取value
*/
public V get(Object key) {
//调用HashMap的getEntry方法获取entry
Entry<K,V> e = (Entry<K,V>)getEntry(key);
if (e == null)
return null;
//这个方法在后面内部类的时候会说到,false时这个方法毫无作用
e.recordAccess(this);
return e.value;
}
/**
* 清空LinkedHashMap,调用父类clear方法,header置空
*/
public void clear() {
super.clear();
header.before = header.after = header;
}
上面介绍了方法的作用,方法里的循环,我们来看一下下面的内部类来了解下
/**
* LinkedHashMap entry.
*/
private static class Entry<K,V> extends HashMap.Entry<K,V> {
// 用于循环的双向链表
Entry<K,V> before, after;
Entry(int hash, K key, V value, HashMap.Entry<K,V> next) {
super(hash, key, value, next);
}
/**
* 删除链表中的entry
*/
private void remove() {
before.after = after;
after.before = before;
}
/**
* 添加entry到集合的尾部
* 这里我刚开始看的时候有点晕,这里大概说下,after与before也是entry
*/
private void addBefore(Entry<K,V> existingEntry) {
after = existingEntry;
before = existingEntry.before;
before.after = this;
after.before = this;
}
/**
* 记录访问次数并将访问过的entry移到尾部
*/
void recordAccess(HashMap<K,V> m) {
LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m;
//只有accessOrder为true时才执行
if (lm.accessOrder) {
lm.modCount++;
remove();
addBefore(lm.header);
}
}
void recordRemoval(HashMap<K,V> m) {
remove();
}
}
上面的内部类介绍了entry的数据结构以及添加时所做的事,还剩下一些东西,下面一起列出来了
//迭代
private abstract class LinkedHashIterator<T> implements Iterator<T> {
Entry<K,V> nextEntry = header.after;
Entry<K,V> lastReturned = null;
/**
* The modCount value that the iterator believes that the backing
* List should have. If this expectation is violated, the iterator
* has detected concurrent modification.
*/
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;
}
}
private class KeyIterator extends LinkedHashIterator<K> {
public K next() { return nextEntry().getKey(); }
}
private class ValueIterator extends LinkedHashIterator<V> {
public V next() { return nextEntry().value; }
}
private class EntryIterator extends LinkedHashIterator<Map.Entry<K,V>> {
public Map.Entry<K,V> next() { return nextEntry(); }
}
// These Overrides alter the behavior of superclass view iterator() methods
Iterator<K> newKeyIterator() { return new KeyIterator(); }
Iterator<V> newValueIterator() { return new ValueIterator(); }
Iterator<Map.Entry<K,V>> newEntryIterator() { return new EntryIterator(); }
/**
* 添加entry
*/
void addEntry(int hash, K key, V value, int bucketIndex) {
//调用父类方法
super.addEntry(hash, key, value, bucketIndex);
// 移除双向链表中近期最少使用的点
Entry<K,V> eldest = header.after;
if (removeEldestEntry(eldest)) {
removeEntryForKey(eldest.key);
}
}
/**
* 添加entry,与addEntry区别是不扩容或移除近期最少使用的点
*/
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++;
}
/**
* 移除双向链表中近期最少使用的点
*/
protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
return false;
}
好了LinkedHashMap分析就到这了