最近在学习Java,有一个问题。
我了解到
HashMap
和 Hashtable
不保留插入顺序或基于键的顺序。但我遇到过不遵循的情况
import java.util.HashMap;
import java.util.Hashtable;
public class Main {
public static void main(String[] args) {
Hashtable<Integer, Integer> hashtableInt = new Hashtable<>();
Hashtable<String, Integer> hashtableStr = new Hashtable<>();
HashMap<Integer, Integer> hashMapInt = new HashMap<>();
HashMap<String, Integer> hashMapStr = new HashMap<>();
for (int i = 0; i < 25; i++) {
hashtableInt.put(i, i);
hashtableStr.put(String.valueOf(i), i);
hashMapInt.put(i, i);
hashMapStr.put(String.valueOf(i), i);
}
System.out.println("Hashtable with Integer keys : ");
for (int key : hashtableInt.keySet()) System.out.print(key + " ");
System.out.println("\n\nHashtable with String keys : ");
for (String key : hashtableStr.keySet()) System.out.print(key + " ");
System.out.println("\n\nHashMap with Integer keys : ");
for (int key : hashMapInt.keySet()) System.out.print(key + " ");
System.out.println("\n\nHashMap with String keys : ");
for (String key : hashMapStr.keySet()) System.out.print(key + " ");
}
}
Hashtable with Integer keys :
24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
Hashtable with String keys :
19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 24 3 23 2 22 1 21 0 20
HashMap with Integer keys :
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
HashMap with String keys :
22 23 24 10 11 12 13 14 15 16 17 18 19 0 1 2 3 4 5 6 7 8 9 20 21 %
在上面的输出中,使用
Integer
键的哈希具有特定的顺序。只有采用 String
作为键的哈希值是没有顺序的。此外,Hashtable
和 HashMap
之间的按键顺序与 Integer
键不同。
所以我想知道的是...
为什么
Hashtable().keySet()
和HashMap().keySet()
有订单?一般来说,哈希和集合没有特定的顺序。这是为什么?我错过了什么吗?
为什么
Hashtable().keySet()
和HashMap().keySet()
的顺序相反?毕竟,这两个都是哈希值,但是内部工作原理是否有所不同?
如果
keySet()
预计有订单,为什么Hashtable().keySet()
和HashMap().keySet()
有不规则订单?
谢谢大家。
我已经调试了
put()
方法并观察了它是如何工作的,但这对我来说太难了。
Hashtable
和HashMap
都是Java集合框架的一部分,实现了Map
接口以通过哈希表存储键值对。 Hashtable().keySet()
和HashMap().keySet()
中看到的“顺序”并不是故意的;它是密钥散列和内部数组处理的产物,无法保证随时间的一致性。对于整数键,由于 Java 的哈希函数特性(由于 Java 的 Integer.hashCode()
方法直接返回整数,键本身被重用为哈希码)以及哈希表如何管理冲突和调整大小,因此该顺序看起来有些可预测。然而,对于字符串键,哈希函数的复杂性会导致顺序难以预测。
Hashtable
和HashMap
之间的顺序差异源于它们不同的实现。 Hashtable
更旧,同步,并且通常更慢,显示出更稳定的迭代顺序。 HashMap
随着时间的推移进行了优化,影响了其迭代顺序的不可预测性。
关键要点是,在这些集合中观察到的顺序是偶然的,受到 Java 哈希机制和集合内部结构的影响。对于有保证的订单,您应该使用
LinkedHashMap
来表示插入顺序,或者如果您想要排序顺序,则应使用 TreeMap
。
您不能依赖订单。虽然这种情况的发生并不是真正的“随机”,但人们绝对可以认为这是偶然的。
这是因为哈希数据结构存储数据的方式。这些依赖于将数据分布在多个存储桶上(通常存储桶的数量多于数据点的数量)。 为了决定哪个数据点进入哪个桶,它调用对象的
hashCode
方法,然后使用模数运算将其分配到桶中。在 Integer
的情况下,这 恰好会返回原始号码。
因此,如果您有 10 个桶并将数字 1,2,3,4,5,5,6 存储在这些桶中,则数字 1 将进入桶 1,而 2 将进入桶 2,依此类推。如果数字分布得更分散,这将不再有效。