根据这些:
HashMap
中的Java
应该是未排序的,但是会根据Key
进行排序。
我认为这是一个问题,因为我需要插入订单数据。所以,我使用LinkedHashMap
代替。但我仍然感到困惑,为什么HashMap
对它进行了排序。
任何人都可以解释一下吗?
我做了一个简单的例子来查看排序。
public static void main(String[] args) {
HashMap<Integer, String> newHashMap = new HashMap<Integer, String>();
newHashMap.put(2, "First");
newHashMap.put(0, "Second");
newHashMap.put(3, "Third");
newHashMap.put(1, "Fourth");
Iterator<Entry<Integer, String>> iterator = newHashMap.entrySet()
.iterator();
while (iterator.hasNext()) {
Map.Entry<Integer, String> entry = iterator.next();
System.out.println("Key: " + entry.getKey());
System.out.println("Value: " + entry.getValue());
iterator.remove();
}
}
结果:
Key: 0
Value: Second
Key: 1
Value: Fourth
Key: 2
Value: First
Key: 3
Value: Third
修改
我尝试使用Random
的{{1}}插入50个随机数,我发现一些数据未排序。但是,它仍然设法对大多数整数进行排序。
随机结果:
Java
答案 0 :(得分:5)
这是巧合(不是真的,而是与散列算法有关)。
尝试添加
newHashMap.put(-5, "Fifth");
最后一次。
输出
Key: 0
Value: Second
Key: 1
Value: Fourth
Key: 2
Value: First
Key: 3
Value: Third
Key: -5
Value: Fifth
javadoc特别说
此课程不保证地图的顺序;特别是,它不保证订单会随着时间的推移保持不变。
答案 1 :(得分:1)
这纯属巧合。有时出现进行排序,但不断添加键,梦想就会破碎。
我写了这个小程序:
import java.util.Map;
import java.util.HashMap;
class MapTest {
public static void main(String[] args){
int count = Integer.parseInt(args[0]);
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
for (int i = 0; i < count; i++) map.put(i, i);
System.out.println(map);
}
}
运行java MapTest 20
时,我得到以下输出(为了便于阅读,换行):
{0=0, 1=1, 2=2, 3=3, 4=4, 5=5, 6=6, 7=7, 8=8, 9=9, 10=10, 11=11, 12=12, 13=13,
14=14, 15=15, 17=17, 16=16, 19=19, 18=18}
这只是HashMap
实现的一个属性,Integer
s顺序添加(从0开始)似乎是有序的。
答案 2 :(得分:1)
你不应该推断太多!仅仅因为三个或四个数字出现排序,这并不意味着已经排序。
正int的哈希码通常只是int,所以如果你的所有键都低于Map维护的内部数组的长度,它们可能会显示为已排序。
尝试使用非常大的值,您会看到令人失望的订单消失。例如,使用
100,200,300,100001,100002,10003,999123456,888777666,....
答案 3 :(得分:1)
你不能假设它会被排序。在这个简单的例子中,它出现排序的原因是:HashMap是从“Bins”内部构造的。这些箱包含实际元素。它们基本上是驻留在数组中的小列表。
[0] -> [ Bin0: ... ]
[1] -> [ Bin1: ... ]
[2] -> [ Bin2: ... ]
[3] -> [ Bin3: ... ]
当一个项插入到HashMap中时,应该插入它的“Bin”是 - 通过使用对象的hashCode()
作为数组索引来简化它。例如,如果hashCode是2,它将被插入到Bin 2.当这个“index”大于数组大小时,它将被放入Bin(索引%arraySize) - 也就是说,如果hashCode是5,它将插入Bin 1。
由于HashMap最初的内部数组大小为10,因此在0到9之间插入Integer
个对象会巧合地将元素以正确的顺序放入数组中。 (当然,Integer的hashCode只是它的值)。
(注意:实际的算法和散列函数可能稍微复杂一点,但这是基本的想法)
答案 4 :(得分:1)
就像每个人都说的那样(并且正确)是你应该假设HashMap中的键没有排序。
现在他们LOOK
按你的理由分类了两个简单的原因:
1 - 您正在使用Integer作为键:HashMap
使用Java的Object类的hashCode()
方法来查找它使用的基础数组中的索引存储Entry
个实例(包含HashMap
中的值和键的内容。恰好,Integer
的哈希码就是它自己的值。
2 - 您没有设置HashMap
的初始大小,因此使用其默认初始大小(即16)。因此,在添加低于0或高于16(包括)的键之前,您将看到按顺序存储的键。由于HashMap
通过执行
int index = newKey.hashCode() % this.capacity;
稍后HashMap
可能会增加其基础数组的容量,如果你插入很多键值对(如果你进入算法和数据结构研究,它决定如何以及何时这样做非常有趣),因此,您最终可能会遇到Integer
个键可能再次排序的情况,但实际上并未对它们进行有意排序。
顺便说一句,如果您的密钥将是整数,并且您可以估计您将要建议直接使用数组的最大密钥值。访问速度更快,使用的内存相同或略少。
答案 5 :(得分:0)
您不能对HashMap对象的排序做出假设。他们将根据需要订购,实施定义。您应该将它们视为无序数据结构。
答案 6 :(得分:0)
实际上无法确保订单。
Hashmap使用哈希码快速哈希数据以进行搜索。
你的钥匙很简单,所以它排序了。
答案 7 :(得分:0)
Mine是一个有根据的猜测,但原因很可能是默认的hashCode方法使用了内存位置。小Integer
的内存位置(以及您的密钥被自动装入Integer
)很可能是固定的:让Integer.valueOf(1)
在多个呼叫上返回不同的内存位置是毫无意义的。最后,这些固定存储器位置很可能是按升序排列的。这可以解释这个巧合,但是,需要深入研究Integer和HashMap的实现来证明这一点。
更正:在Integer的情况下“此对象的哈希码值,等于此Integer对象表示的原始int值。” (JavaDoc的)。虽然数字不同,但确认了这个想法。
答案 8 :(得分:0)
由于没有真正用于查看Java源代码的答案,我会这样做! :)
当您调用put()
函数时,内部散列函数使用对象的hashCode来生成散列索引。 [put()
source]
hash()
函数只是确保在每个位位置只有常数倍数的hashCodes具有有限的碰撞次数[使用Google查看为什么会这样]。
事情恰巧在这里奏效了。就是这样。
答案 9 :(得分:0)
提问者说:
“Java 中的 HashMap 应该是未排序的,但它是根据 Key 进行排序的。”
是,对的。我将向您展示以下示例
Map<String, String> map1 = new HashMap<String, String>();
map1.put("c","xxxx");
map1.put("b","yyyy");
map1.put("a","zzzz");
for (String key :map1.keySet())
System.out.println(map1.get(key));
System.out.println();
Map<Integer,String> map2 = new HashMap<Integer,String>();
map2.put(3,"xxxx");
map2.put(2,"yyyy");
map2.put(1,"zzzz");
for (int key :map2.keySet())
System.out.println(map2.get(key));
输出显示HashMap使用Key对数据进行排序
xxxx
yyyy
zzzz
zzzz
yyyy
xxxx