这是我们用来放入hasmap的类。它已覆盖equals()
和hashcode()
方法。
class Dog
{
public String name;
public Dog(String n)
{
name=n;
}
@Override
public int hashCode() {
System.out.println("in hashcode");
return name.length();
}
@Override
public boolean equals(Object obj) {
System.out.println("in equals");
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Dog other = (Dog) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
此代码在主要
中Map<Object,Object> m=new HashMap<Object,Object>();
Dog d1=new Dog("clover");
m.put(d1,"Dog Key");
System.out.println(m.get(d1));
生成
in hashcode
in hashcode
Dog Key
但是以下代码为
Map<Object,Object> m=new HashMap<Object,Object>();
Dog d1=new Dog("clover");
m.put(d1,"Dog Key");
System.out.println(m.get(new Dog("clover")));
产生
in hashcode
in hashcode
in equals
Dog Key
正如您所看到的,在第二个输出中调用了equals()
方法。为什么会这样?
我的第二个问题
如果我更改密钥的name属性
Map m = new HashMap();
Dog d1=new Dog("clover");
m.put(d1,"Dog Key");
d1.name="arthur";
System.out.println(m.get(new Dog("clover")));
o / p是
in hashcode
in hashcode
in equals
null
即使我更改了键值,但我试图通过提供相同的键来检索值。那么为什么它会检索null?
答案 0 :(得分:3)
对于第一个问题:HashMap
需要调用equals()
来确认两个具有相同哈希码的Dog
个对象实际上是相等的。它不需要第一次调用equals()
,因为它使用==
来检查使用与先前指定的完全相同的对象的特殊情况。
对于第二个问题:您更改了一个数据成员,该成员更改了哈希码的计算和equals()
的结果。这是专门针对规则的,因此地图已损坏;在那一点上,任何事情都可能发生。永远不要将具有可变数据的对象用于HashMap
!
答案 1 :(得分:1)
这是因为在将d1=new Dog("clover")
放入hashmap后,您将其名称更改为d1.name="arthur";
,因此名称为arthur
的Dog不再等于new Dog("clover")
。
因此,首先检查密钥哈希码,然后匹配,因为"clover".length
等于"arthur".length
,这样可以识别保存对象的存储桶。之后执行equals()
检查以从存储桶中获取正确的对象,并且由于您的密钥不等于提供的密钥而失败。
实际上,使用可变字段进行哈希码计算并不是一个好习惯。
答案 2 :(得分:1)
让我们考虑一下HashMap的工作原理。
使用正确的哈希码算法和HashMap的容量设置允许在put上达到O(1)性能并获得通常。
现在让我们考虑一下你的问题:
但是如果你改变你的代码:
Dog d1=new Dog("clover");
m.put(d1,"Dog Key");
d1.name="arthur";
System.out.println(m.get(d1));
它应该最终给你一个。