我正在努力解释为什么我得到第二行输出为" Line2:null"在HashMap上运行以下代码时:
import java.util.*;
class Dog {
public Dog(String n) {name = n;}
public String name;
public boolean equals(Object o) {
if((o instanceof Dog) && (((Dog)o).name == name)) {
return true;
}
else {return false;}
}
public int hashCode() {return name.length();}
}
public class HelloWorld{
public static void main(String []args){
Map<Object, Object> m = new HashMap<Object, Object>();
Dog d1 = new Dog("clover");
m.put(d1, "Dog key");
System.out.println("Line1: " + m.get(d1));
d1.name = "magnolia";
System.out.println("Line2: " + m.get(d1));
d1.name = "clover";
System.out.println("Line3: " + m.get(new Dog("clover")));
d1.name = "arthur";
System.out.println("Line4: " + m.get(new Dog("clover")));
}
}
显示的输出是:
第1行:狗钥匙
Line2:null
第3行:狗钥匙
Line4:null
是的,我确实意识到,由于我计算哈希码的方式,反过来修改实例变量 name 会影响Dog实例的哈希码。但是,我使用相同的实例作为密钥!那么,为什么get()方法不能找到相应的值呢?似乎一旦将一对推入HashMap,关键就是永久硬编码!它是如何工作的,这意味着,一旦在HashMap中放置该对之前确定了一个值的哈希码,就不能再次修改哈希码?
答案 0 :(得分:0)
是的,我确实意识到,由于我计算哈希码的方式,修改实例变量名反过来会影响Dog实例的哈希码。但是,我使用相同的实例作为密钥!那么,为什么get()方法不能找到相应的值?
这种解释有点过于简单,但它仍然应该说明这里发生了什么。将HashMap视为键值对的数组。 hashCode值用于决定获取/放置给定值的索引。
例如,如果您的哈希代码返回7,那么它将尝试获取/将值放在数组中的索引7处。所以,让我们说你正在进行put
操作,但索引7已经满了。有几种方法可以解决这个问题,但最简单的方法是在每个数组索引处都有一个带有相同哈希值的存储桶(例如链接列表),然后添加新的桶的价值。
现在让我们说你正在进行get
操作。您检查数组中与您的哈希值对应的索引 - 但您不能保证您正在寻找的值(由于可能的哈希冲突)。您需要确保该位置的密钥对于用于查找的密钥也是equal
。如果键不相等,那么你继续寻找(在桶中)。如果没有任何地方可以查看(即您已经搜索过整个广告素材),那么该值就不在地图中。
这是您的代码破坏的部分。您正在查找正确的存储桶(因为您的密钥的哈希值与原始哈希值相同),但是当您执行&#34;深度&#34;时,equals
方法现在返回false。比较以检查您确实拥有正确的键/值对。
它是如何工作的,这意味着,一旦在HashMap中放置该对之前确定了一个值的哈希码,就不能再次修改哈希码?
当您了解如何使用数组实现HashMap时(如上所述),显然这实际上是预期的行为,并且改变键是一个非常糟糕的想法
一些旁注......
您应该使用equals
来比较名称:
((Dog)o).name.equals(name))
以下是您目前拥有的内容:
((Dog)o).name == name)
检查name
字符串是否是相同的实例而不是字符串具有相同的值。
您可以通过返回逻辑操作的结果来简化equals
方法:
public boolean equals(Object o) {
return (o instanceof Dog) && (((Dog)o).name.equals(name));
}