【发布时间】:2016-10-11 04:36:07
【问题描述】:
public class HashMapKeySet {
public static void main(String[] args) {
Map<HashCodeSame,Boolean> map=new HashMap();
map.put(new HashCodeSame(10),true);
map.put(new HashCodeSame(2),false);
for(HashCodeSame i:map.keySet())
System.out.println("Key: "+i+"\t Key Value: "+i.getA()+"\t Value: "+map.get(i)+"\t Hashcode: "+i
.hashCode());
System.out.println("\nEntry Set******");
for(Map.Entry<HashCodeSame, Boolean> i:map.entrySet())
System.out.println("Key: "+i.getKey().getA()+"\t Value: "+i.getValue()+"\t Hashcode: "+i.hashCode());
System.out.println("\nValues******");
for(Boolean i:map.values())
System.out.println("Key: "+i+"\t Value: "+map.get(i)+"\t Hashcode: "+i.hashCode());
}
static class HashCodeSame{
private int a;
public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
HashCodeSame(int a){
this.a=a;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
HashCodeSame that = (HashCodeSame) o;
return a == that.a;
}
@Override
public int hashCode() {
return 1;
}
}
}
如果您可以在上面的示例中看到,我已经明确地让 hashcode() 在所有情况下都返回 1,以检查当 hashmap 中 key.hashcode() 发生冲突时会发生什么。会发生什么,为这些 Map.Entry 对象维护一个链表,例如
1(key.hashcode()) 将链接到 将链接到
(据我所知,在真值之后输入假值)。
但是当我做keySet()时,先返回true,然后返回false,而不是先返回false。
所以,我在这里假设的是,因为 keySet() 是一个集合并且集合保持顺序,所以我们在迭代时得到真假。但是,话又说回来,我们为什么不说 hashmap 保持顺序,因为检索的唯一方法是按顺序。或者我们为什么要使用 LinkedHashMap?
Key: DS.HashMapKeySet$HashCodeSame@1 Key Value: 10 Value: true Hashcode: 1
Key: DS.HashMapKeySet$HashCodeSame@1 Key Value: 2 Value: false Hashcode: 1
Entry Set******
Key: 10 Value: true Hashcode: 1230
Key: 2 Value: false Hashcode: 1236
Values******
Key: true Value: null Hashcode: 1231
Key: false Value: null Hashcode: 1237
现在,当我添加 chsnge 时,hashcode 方法会返回一个赞
@Override
public int hashCode() {
return a;
}
我得到相反的顺序。再加上
map.put(new HashCodeSame(10),true);
map.put(new HashCodeSame(2),false);
map.put(new HashCodeSame(7),false);
map.put(new HashCodeSame(3),true);
map.put(new HashCodeSame(9),true);
收到的输出是,
Key: DS.HashMapKeySet$HashCodeSame@2 Key Value: 2 Value: false Hashcode: 2
Key: DS.HashMapKeySet$HashCodeSame@3 Key Value: 3 Value: false Hashcode: 3
Key: DS.HashMapKeySet$HashCodeSame@7 Key Value: 7 Value: false Hashcode: 7
Key: DS.HashMapKeySet$HashCodeSame@9 Key Value: 9 Value: true Hashcode: 9
Key: DS.HashMapKeySet$HashCodeSame@a Key Value: 10 Value: true Hashcode: 10
Entry Set******
Key: 2 Value: false Hashcode: 1239
Key: 3 Value: false Hashcode: 1238
Key: 7 Value: false Hashcode: 1234
Key: 9 Value: true Hashcode: 1222
Key: 10 Value: true Hashcode: 1221
Values******
Key: false Value: null Hashcode: 1237
Key: false Value: null Hashcode: 1237
Key: false Value: null Hashcode: 1237
Key: true Value: null Hashcode: 1231
Key: true Value: null Hashcode: 1231
现在这又让我想知道,为什么顺序是有序的。?谁能详细解释一下 hashmap 的 keySet()、entrySet() 方法是如何工作的?
【问题讨论】:
-
那是因为添加相同哈希码的项目最终都在同一个桶中,并且插入顺序被保留,如果您有分布式哈希码则不是这种情况。对所有对象使用相同的哈希码是个坏主意。
-
“如果 keySet() 维护 HashMap 的顺序,为什么我们需要 LinkedHashMap?”哈希映射键的顺序是未定义的;如果您看到它们以您期望的顺序出现,那是巧合,并不保证总是如此。
-
你能让我理解keySet()的内部实现吗?正如在这个stackoverflow.com/questions/1882762/… 链接中给出的那样,keySet 总是与输入的顺序相同,尽管迭代它会比迭代linkedHashMap 更昂贵。
-
构造一个迭代顺序 != 插入顺序的例子是微不足道的,例如ideone.com/SOe3Qh。 您无需了解内部实现。您只需要知道
HashMap的迭代顺序无法保证。 -
如果您可以构造一个恰好保留了排序的示例,这并不重要:
HashMap没有排序保证,所以这仅仅是巧合:您不能依赖排序存在保存。
标签: java collections hashmap linkedhashmap keyset