LinkedHashMap在Java中的实现

时间:2015-04-15 06:14:59

标签: java linkedhashmap

我无法理解LinkedHashMap HashFunction 的用法。

在HashMap实现中, hashFunction 的使用是根据 hashfunction 契约找到内部数组的索引,这可以是合理的(相同key必须具有相同的哈希码,但不同的键可以具有相同的哈希码)。

我的问题是:

1)LinkedHashMap哈希函数的用途是什么?

2) put and get 方法如何适用于LinkedHashMap

3)为什么它在内部维护双重链接列表? 使用HashMap作为内部实现(就像HashSet)并在条目数组中维护单独的数组/列表错误是错误的插入顺序?

感谢有用的回应和参考。

4 个答案:

答案 0 :(得分:2)

1)LinkedHashMap扩展了HashMap,因此hash函数与HashMap相同(如果检查代码,哈希函数是从HashMap继承的),即函数计算插入对象的哈希值并用于存储数据结构与具有相同键哈希的元素一起;在get方法中使用hasfunction来检索具有指定为param的键的对象。

2)Put和Get方法的行为与HashMap相同,加上跟踪元素的插入顺序,因此当您遍历键集时,您将按照插入到地图中的顺序获取键值(请参阅{{ 3}}了解更多细节)

3)LinkedHashMap使用双链表而不是数组,因为它更紧凑;双链表是插入和删除项目的列表中最有效的数据结构;如果你主要插入/追加元素,那么基于数组的实现可能会更好。由于map sematic是一个键值实现,并且从地图中删除元素可能是一个频繁的操作,因此双链表更适合。可以使用LinkedList进行内部实现,但我的意见是使用低级数据结构更有效,并将LinkedHashMap与其他类分离。

答案 1 :(得分:1)

LinkedHashMap对于您希望能够putget条目运行O(1)的数据结构是一个不错的选择,但您还需要这种行为一个LinkedList。内部散列函数允许putget条目具有恒定时间。

以下是您使用LinkedHashMap的方式:

Map<String, Double> linkedHashMap = new LinkedHashMap<String, String>();
linkedHashMap.put("today", "Wednesday");
linkedHashMap.put("tomorrow", "Thursday");
String today = linkedHashMap.get("today"); // today is 'Wednesday'

有几个论点反对使用简单的HashMap并为插入顺序维护单独的List。首先,如果你走这条路线就意味着你将不得不维护2个数据结构而不是一个。这很容易出错,并且使代码维护变得更加困难。其次,如果必须使数据结构具有线程安全性,那么对于2个数据结构来说这将是复杂的。另一方面,如果你使用LinkedHashMap,你只需要担心这个单一数据结构是线程安全的。

至于实现细节,当您在put中执行LinkedHashMap时,JVM将获取您的密钥并使用加密映射功能最终将该密钥转换为内存地址,其中您的值将是存储。使用给定键执行get也将使用此映射函数来查找存储值的内存中的确切位置。 entrySet()方法返回Set,其中包含LinkedHashMap中的所有键和值。根据定义,集合不是有序的。 entrySet()不保证是线程安全的。

答案 2 :(得分:0)

LinkedHashMap 使用HashMap(事实上它是从它扩展而来),因此hashCode用于识别正确的哈希桶哈希桶数组,与HashMap一样。 putget的工作方式与HashMap的工作方式相同(除了用于迭代条目的beforeafter引用对两个实现的更新方式不同)。

保留ArrayArrayList不能保留插入顺序的原因是ArrayList中间的添加或移除是O(n)操作,因为您有将所有后续项目移动到一个地方。您可以使用LinkedList执行此操作,因为LinkedList中间的添加和删除是O(1)(您只需要打破一些链接并创建一些新链接)。但是,使用单独的LinkedList没有意义,因为您也可以让Map.Entry个对象引用上一个和下一个Entry对象,这正是LinkedHashMap的工作方式。

答案 3 :(得分:-2)

答。 2) 当我们调用linkedhashmap的put(map,key)时。在内部,它调用createEntry

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;
e.addBefore(header);
size++;

Ans 3) 为了有效地维护linkedHashmap,您实际上需要一个双向链表。

按顺序考虑三个条目

A ---&gt; B ---&gt; ç

假设您要删除B.显然A现在应指向C.但除非您知道B之前的条目,否则您无法有效地说出哪个条目现在应指向C.要解决此问题,您需要输入以指向方向像这样

---&GT; ---&GT;

A B C

&lt; ---&lt; ---

这样,当您删除B时,您可以查看B(A和C)之前和之后的条目并进行更新,以便A和C相互指向。 前面讨论的这个链接中的类似帖子

why linkedhashmap maintains doubly linked list for iteration