我正在尝试找出 HashMap 中的值的检索顺序。这是相同的代码片段。
import java.util.HashMap;
public class HashMapExample {
public static void main(String[] args) {
HashMap<Integer, String> hashmap = new HashMap<Integer, String>();
hashmap.put(1, "apple" );
hashmap.put(2, "lemon" );
hashmap.put(3, "orange" );
hashmap.put(4, "banana" );
hashmap.put(5, "litchi" );
hashmap.put(6, "mango" );
hashmap.put(7, "papaya" );
System.out.println(hashmap.size());
for (String key : hashmap.values()) {
System.out.println(key);
}
}
}
7
apple
lemon
orange
banana
litchi
mango
papaya
这些值按照插入的顺序打印。总体来说这是真的吗?我期望以任意顺序打印这些值。这是使用 Java 6。
HashMap
“类不保证映射的顺序;特别是,它不保证顺序随着时间的推移保持不变。”
LinkedHashMap
(用于插入/访问顺序)或 TreeMap
(用于比较顺序)。请注意,这些保持键的顺序,而不是值的顺序。
这些值按照插入的顺序打印。总体来说这是真的吗?我期望这些值以随机顺序打印。
HashMap
API 未定义迭代顺序。
但是,如果你看一下 HashMap 的实现,你可以推断出迭代顺序、键的哈希值、键插入的顺序和哈希表的大小之间存在复杂的瞬态关系。如果哈希表自行调整大小,这种关系就会变得混乱1。
在您的情况下,您使用的是
Integer
键,这意味着键的哈希值就是键值本身。此外,您还按按键顺序插入了条目。这导致(偶然地!)迭代顺序与插入顺序匹配。但如果你不断插入更多的键,你会发现迭代顺序“环绕”。然后,随着表格经历一系列大小调整,顺序将逐渐变得越来越混乱。
简而言之,您所看到的是哈希表实现和特定
hashCode
方法的产物。它不是您可以(或应该)明智地利用的东西。尤其是因为它可以从一个 Java 版本更改为下一个版本(并且已经更改)!
1 - 或者在 Java 8 或更高版本中,如果特定哈希桶/哈希链的拥塞导致其从简单列表切换到红黑树。深入的实施细节。如果您好奇,请阅读源代码!
A LinkedHashMap 就是您所追求的。从 doco 来看,它与 HashMap 不同,因为它维护一个贯穿其所有条目的双向链表
如果顺序很重要,请尝试 LinkedHashMap...请参阅 JavaDoc
公共类 LinkedHashMap 扩展 哈希映射
哈希表和链表 地图接口的实现, 具有可预测的迭代顺序。这 实现与 HashMap 的不同之处在于 它维护一个双向链表 遍历其所有条目。 这个链表定义了迭代 ordering,通常是顺序 其中钥匙被插入到 地图(插入顺序)。注意 插入顺序不受影响,如果 密钥被重新插入到地图中。 (A 密钥 k 被重新插入到映射 m 中,如果 m.put(k, v) 被调用时 m.containsKey(k) 将返回 true 就在调用之前。)
相关的集合是 java.util.concurrent 的 ConcurrentSkipListMap。 skiplist 允许您按键顺序遍历条目,也可以按随机顺序查看它们(但不如 HashMap 快)。
有一个不错的跳过列表演示小程序。
不,在 HashMap 中不会保留顺序(如果您想要排序实现。) 如果您希望对键进行排序,可以使用 TreeMap。
例如- {[3=1],[2=50],[20=4],[14=1]} -> HashMap
对于 TreeMap,你得到 - {[2=50],[3=1],[14=1],[20=4]} -> TreeMap