今天有个需求,要求把某个公司和这个公司的有序产品放到map中存储,同时放入这个map中的公司时有顺序要求的——什么顺序放进去,什么顺序拿出来!
用普通的HashMap解决这个需求就不合适了。jdk提供的集合框架中的LinkedHashMap比较适合这个需求。那么他又是怎么实现这个功能的呢?一起来看看源码吧。
public class LinkedHashMap<K,V>
extends HashMap<K,V>
implements Map<K,V>
这里可以看出,LinkedHashMap就是HashMap的一个子类。
static class Entry<K,V> implements Map.Entry<K,V> {
final K key;
V value;
final int hash;
Entry<K,V> next;
private static class Entry<K,V> extends HashMap.Entry<K,V> {
// 可以看到在HashMap.Entry基础上,增加了下面两个属性!
// These fields comprise the doubly linked list used for iteration.
Entry<K,V> before, after;
public V put(K key, V value) {
//从这里可以看出,HashMap是允许以null为key的存储的!
if (key == null)
return putForNullKey(value);
int hash = hash(key.hashCode());
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++;
//LinkedHashMap override了下面这个方法!
addEntry(hash, key, value, i);
return null;
}
- 那么put时,两个方法最大的区别就是上面的这个addEntry方法了,分别看一下:
//HashMap中的方法
void addEntry(int hash, K key, V value, int bucketIndex) {
Entry<K,V> e = table[bucketIndex];
//这里可以看出,如果hash不均匀的话,会造成table中的某些entry元素比较庞大(因为里面会嵌套N层的子entry)
table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
if (size++ >= threshold)
resize(2 * table.length);
}
//LinkedHashMap中的方法
void addEntry(int hash, K key, V value, int bucketIndex) {
createEntry(hash, key, value, bucketIndex);
// Remove eldest entry if instructed, else grow capacity if appropriate
Entry<K,V> eldest = header.after;
//这里LinkedHashMap本身的removeEldestEntry方法是直接返回false的,但他的N个子类可能会采用不用的淘汰老元素的策略。
if (removeEldestEntry(eldest)) {
removeEntryForKey(eldest.key);
} else {
if (size >= threshold)
resize(2 * table.length);
}
}
void createEntry(int hash, K key, V value, int bucketIndex) {
HashMap.Entry<K,V> old = table[bucketIndex];
Entry<K,V> e = new Entry<K,V>(hash, key, value, old);
table[bucketIndex] = e;
//注意:这里将新创建的元素插入到连表里header的前面(也就是Map的put方法中将entry加入双向链表的地方)
e.addBefore(header);
size++;
}
- 剩下就是看LinkedHashMap是如何实现这个按插入的顺序展示entrySet中的元素了:
//HashMap中的EntryIterator中的nextEntry方法
Entry<K,V> nextEntry() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
Entry<K,V> e = next;
if (e == null)
throw new NoSuchElementException();
Entry<K,V> n = e.next;
Entry[] t = table;
int i = index;
while (n == null && i > 0)
n = t[--i];
index = i;
next = n;
return current = e;
}
//LinkedHashMap重新定义了自己的内部类EntryIterator(当然其实HashMap中的EntryIterator也是private的),这里关键的不同就在这个nextEntry方法了
Entry<K,V> nextEntry() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
if (nextEntry == header)
throw new NoSuchElementException();
Entry<K,V> e = lastReturned = nextEntry;
//关键在这里,会将nextEntry指向当前元素的下一个元素!
nextEntry = e.after;
return e;
}
好了,关键原理找到了,其实其中还有很多细节,不过对理解原理不重要,可以暂时忽略!
分享到:
相关推荐
持久化 LinkedHashMap Java LinkedHashMap 的 Haskell 实现。 底层 HashMap 基于 Data.HashMap.Strict。 两种不同的实现基于 Data.Sequence 和 Data.IntMap.Strict 来保持键的插入顺序。 标准报告: :
主要介绍了Java使用LinkedHashMap进行分数排序的相关代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
本文主要介绍了Java中LinkedHashMap的相关知识,具有很好的参考价值。下面跟着小编一起来看下吧
主要为大家详细介绍了Java集合系列之LinkedHashMap源码分析,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
主要介绍了 java HashMap,TreeMap与LinkedHashMap的详解的相关资料,这里提供实例代码,帮助大家学习理解 这部分的内容,需要的朋友可以参考下
主要为大家解析了Java中LinkedHashMap源码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
将LinkedHashMap转换为json,反之亦然 如何使用 LinkedHashMap requestData = new LinkedHashMap(); LinkedHashMap auth =新的LinkedHashMap(); auth.put(“ ServiceName”,“ Login”); auth.put(“ ...
LinkedHashMap是Java中的一种特殊类型的HashMap,它保留了插入顺序,即按照元素插入的先后顺序进行排序
RiteLinked——类似HashMap的容器,以用户可控的顺序保存它们的键值对RiteLinked提供了LinkedHashMap和LinkedHashSet更多最新版本。您可以在std或no_std环境中轻松使用它。一些实用的功能组合,支持,帮助您更好地将...