HashMap本质上存储数据是无序的,但是某些情况下使用foreach循环时输出似乎有序,这实际上是由于哈希表的实现细节和哈希冲突的处理方式导致的巧合现象。
hashMap无序性的本质:
1.hashMap的实现是基于哈希表+链表/红黑树实现
1.哈希表决定健的位置(桶的位置)
2.链表/红黑树处理哈希冲突
3.迭代顺序是由哈希表的桶遍历顺序和链表遍历顺序共同决定。
2.为什么foreach有时看起来有序:
1.小数据集且hash冲突少
当数据集较小时,健的哈希值可能正好分布在连续的桶中:
HashMap<Integer,String>map=new HashMap<>();
map.put(1,"A");
map.put(2,"B");
map.put(3,"C");
//输出可能巧合地显示顺序为:1=A, 2=B, 3=C
map.forEach((key,value)->System.out.println(key+"="+value));
2.哈希计算的特殊性:
如果健的哈希值经过扰动后恰好按照插入顺序排列,遍历时会呈现有序的假象。
例如使用Integer作为健时,哈希值直接等于数值。
map.put(10, "X"); // 哈希值=10,落入桶10
map.put(20, "Y"); // 哈希值=20,落入桶20
map.put(30, "Z"); // 哈希值=30,落入桶30
3.扩容未发生:
当哈希表未发生扩容时,现有健的存储位置不会改变,若后续插入的健哈希值递增,遍历桶时会顺序输出。
3.有序替代方案:
特性 | HashMap | LinkedHashMap | TreeMap |
顺序保证 | 无 | 插入顺序/访问顺序 | 自然排序/自定义排序 |
时间复杂度 | O(1) | O(1) | O(log n) |
内部结构 | 哈希表 | 哈希表+双向链表 | 红黑树 |
使用场景 | 快速查找 | 需要保留插入顺序的场景 | 需要排序的场景 |