为什么重写equals方法还要重写hashcode方法
举例说明
只重写equals方法
class B {
private String name;
public B(String name) {this.name = name;}
public boolean equals(Object o) {
if (this == o) return true;
B b = (B) o;
return name == b.name;
}
}
B b1 = new B("1");
B b2 = new B("1");
System.out.println(b1.equals(b2)); // true
System.out.println(b1.hashCode()); // 460141958
System.out.println(b2.hashCode()); // 1163157884
// 会发现,它们内容相同了,但是hash值却不相同
// 如果这时使用B类元素来作为Map集合的key,那么map中就会存在重复内容的元素
// 因为map是跟据hash来计算索引位置的,而这时它们的hash值不相同,所以可以直接添加到map集合中(hash不同索引位置不同)
【跟据hash来计算索引位置是java开发者为了减少hash冲突概率的一种算法】
只重写hashcode方法
class C {
private String name;
public C(String name) {
this.name = name;
}
public int hashCode() {
return Objects.hash(name);
}
}
C c1 = new C("1");
C c2 = new C("1");
System.out.println(c1.hashCode()); // 80
System.out.println(c2.hashCode()); // 80
System.out.println(c1.equals(c2)); // false
/*
可以看出上面hash值相同了,但是equals比较它们却不相同,默认equals方法比较的是内存地址
假设现在用C类元素作为hashMap集合的key,c1已经添加到容器中了,这时添加c2,当它们判断到它们key相同时,就会继 续调用C类中的equals方法来比较 因为没有重写,所以比较的是c1和c2的内存地址,因为不同,所以添加成功了。
但是这种情况下是不允许的,为什么。
因为它们的内容 name属性都是"1", 从人类思维上来说,它们的内容是一样的啊,按理说一样的属性equals应该判断为
true才对,但是因为equals方法默认比较的是内存地址
所以这个时候需要重写equals方法来比较它们的name属性是否相同。这个时候计算机就知道c1和c2它们的内容是相同的
*/
重写equals和hashcode方法
class D {
private String name;
public D(String name) {this.name = name;}
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
D d = (D) o;
return name == d.name;
}
public int hashCode() {
return name.hashCode();
}
}
D d1 = new D("1");
D d2 = new D("1");
System.out.println(d1.equals(d2)); // true
System.out.println(d1.hashCode()); // 49
System.out.println(d2.hashCode()); // 49
/*
在重写了两个方法后,我们来用D类作为hashMap的key来使用
当d1添加进去后,又添加了d2时,这时会通过hash值计算出当前元素在容器中的索引位置,因为hash值相同,所以在d1
添加的时候,假设它的索引位置时4,这时d2也通过计算后其索引也为4,这时就会判断d1和d2的hash值是否相同,相同则 继续比较它们的内容是否相同,就会调用D类中的equals方法,比较的是它们内部的name属性是否相同,又因为name属性是
字符串类型,所以"1"值指向都是常量池中同一个对象,最后执行 return name == d.name; 比较后发现它们的name属性 相同,所以hashmap就会认为当前要添加的元素的key在容器中已经存在,那么就会将新的元素覆盖掉容器中已存在的元素。
*/
结论:在确保不允许有重复元素的情况下,必须重写两个方法。