Java 使用HashMap时的奇怪行为

Java 使用HashMap时的奇怪行为,java,hashmap,treemap,Java,Hashmap,Treemap,我正在尝试修复一个代码,我将无法在这里发布它,所以我在这里有一个精简版本 在使用HashMap时,我得到了一个不稳定的输出 HashMap<Integer, String> test= new HashMap<>(); test.put(1, "one"); test.put(2, "one"); test.put(3, "one"); test.put(4,"four"); test.put(5, "one"); test.put(6, "one"); test.p

我正在尝试修复一个代码,我将无法在这里发布它,所以我在这里有一个精简版本

在使用HashMap时,我得到了一个不稳定的输出

HashMap<Integer, String> test= new HashMap<>(); 
test.put(1, "one");
test.put(2, "one");
test.put(3, "one"); 
test.put(4,"four");
test.put(5, "one");
test.put(6, "one");
test.put(10, "one");
test.put(19, "one");    
test.put(20, "Sixteen");    
System.out.println(test);


HashMap<Integer, String> test3= new HashMap<>(200); 
test3.put(1, "one");
test3.put(2, "one");
test3.put(3, "one");    
test3.put(4,"four");
test3.put(5, "one");
test3.put(6, "one");
test3.put(10, "one");
test3.put(19, "one");   
test3.put(20, "Sixteen");
System.out.println(test3);  
为什么即使输入值相同,结果也不同。这种排序(即存储元素)有何不同

我无法使用第二种方法,因为大小是动态的,它会根据应用程序不断变化。我可以对同一个值使用TreeMap并获得所有值的一致输出吗。

这是因为

new HashMap()构造一个具有默认初始容量(16)的空HashMap

因此,它倾向于打印索引0->15的值,然后再从索引16-->31打印被认为是0->15的值。

这是因为

new HashMap()构造一个具有默认初始容量(16)的空HashMap

因此,它倾向于打印索引0->15的值,然后从被认为是0->15的索引16-->31再次打印。

HashMap
类的条目

此类不保证地图的顺序;特别是,它不能保证订单在一段时间内保持不变

HashMap
类的条目中

此类不保证地图的顺序;特别是,它不能保证订单在一段时间内保持不变

当尺寸不同时,为什么输出不同——

这是因为在调用hashmap indexFor(hash,table.length)的put方法时会在内部调用。Table.length不同,这意味着默认值为16,但对于第二种方式,大小为200。所以索引会有所不同

请阅读更多这篇文章

我可以对同一个值使用TreeMap并获得所有值的一致输出吗

在树映射保证中,键将被排序,因此您将得到
{1=1,2=1,3=1,4=4,5=1,6=1,10=1,19=1,20=16}

如果您想按顺序检索其插入方式,可以使用LinkedHashmap

为什么大小不同时输出不同——

这是因为在调用hashmap indexFor(hash,table.length)的put方法时会在内部调用。Table.length不同,这意味着默认值为16,但对于第二种方式,大小为200。所以索引会有所不同

请阅读更多这篇文章

我可以对同一个值使用TreeMap并获得所有值的一致输出吗

在树映射保证中,键将被排序,因此您将得到
{1=1,2=1,3=1,4=4,5=1,6=1,10=1,19=1,20=16}


如果要按顺序检索其插入的HashMap

HashMap
不提供顺序保证,则可以使用LinkedHashmap。如果要根据插入的顺序检索map中的元素,可以使用
LinkedHashMap

HashMap
不提供顺序保证。如果要根据插入的顺序检索map中的元素,可以将
LinkedHashMap

与HashMaps一起使用,有一个称为加载因子的概念。加载因子是hashmap在调整自身大小之前的填充量。如果加载因子为0.5(或50%),那么当hashmap达到50%的容量时,它将调整自身大小,以便为更多元素腾出空间

hashmap的加载因子通常小于100%的原因是元素的存储方式。生成哈希时,使用哈希函数。您正在使用的哈希函数是默认值,它基于对象的equals()方法,并存储了一些目前并不重要的额外旋转。问题是,两个元素可能以相同的哈希结束,但不能保证它是唯一的。当您尝试使用相同的散列存储两个值时,它们最终会出现在hashmap中的同一个“bucket”中。这叫做碰撞。当发生冲突时,hashmap需要一个策略来处理它

有时策略是“线性探测”。这意味着,如果一个元素发生冲突,hashmap将在接下来的几个桶中寻找一个空桶

有时,策略是“链接”,如果元素发生冲突,hashmap将用链表替换现有元素,并将每个发生冲突的元素放在列表中

这意味着,当元素在hashmap中发生冲突时,插入和检索元素的速度会变慢。因此,为了减少冲突的机会,hashmap根据负载因子调整自身大小


除此之外,正如其他人所提到的,在基本HashMap中没有排序的保证。您需要使用像LinkedHashMap这样的实现。

对于HashMaps,有一个称为加载因子的概念。加载因子是hashmap在调整自身大小之前的填充量。如果加载因子为0.5(或50%),那么当hashmap达到50%的容量时,它将调整自身大小,以便为更多元素腾出空间

hashmap的加载因子通常小于100%的原因是元素的存储方式。生成哈希时,使用哈希函数。您正在使用的哈希函数是默认值,它基于对象的equals()方法,并存储了一些目前并不重要的额外旋转。问题是,两个元素可能以相同的哈希结束,但不能保证它是唯一的。当您尝试使用相同的散列存储两个值时,它们最终会出现在hashmap中的同一个“bucket”中。这叫做碰撞。当发生冲突时,hashmap需要一个策略来处理它

有时策略是“线性探测”。这意味着,如果一个元素发生冲突,hashmap将在接下来的几个桶中寻找一个空桶

有时,策略是“链接”,如果元素发生冲突,hashmap将用链表替换现有元素,并将每个发生冲突的元素放在列表中

所有这些都意味着
test --> {1=one, 19=one, 2=one, 3=one, 4=four, 20=Sixteen, 5=one, 6=one, 10=one}
test3--> {1=one, 2=one, 3=one, 4=four, 5=one, 6=one, 10=one, 19=one, 20=Sixteen}---> My desired output. 
Map<Integer, String> test= new TreeMap<>(); 
test.put(1, "one");
test.put(2, "one");
test.put(3, "one"); 
test.put(4,"four");
test.put(5, "one");
test.put(6, "one");
test.put(10, "one");
test.put(19, "one");    
test.put(20, "Sixteen");    
System.out.println(test); // Output : {1=one, 2=one, 3=one, 4=four, 5=one, 6=one, 10=one, 19=one, 20=Sixteen}