一、前言
在完成实验二的ConcreteEdgesGraph类时,我遇到这样一个问题,在已经重写了equal方法后,判断一个Set中是否包含某个元素时返回错误,在我的预想中本应返回false却返回了true。
package test;
import java.util.HashSet;
import java.util.Set;
public class Main {
private final Set<Person> vertices = new HashSet<>();
public static void main(String[] args) {
Main graph = new Main();
Person p_1 = new Person("a");
Person p_2 = new Person("a");
System.out.println(graph.vertices.add(p_1));
System.out.println(graph.vertices.add(p_2));
}
public boolean add(Person vertex) { //添加点,若点已存在则返回false
//throw new RuntimeException("not implemented");
if (vertices.contains(vertex)) {
return false;
} else {
vertices.add(vertex);
return true;
}
}
}
package test;
public class Person {
private String name; //姓名
public boolean visit = false; //记录是否已遍历
public int distance; //记录距离
public Person(String name) {
this.name = name;
}
public String nameGetter() {
return this.name;
}
@Override public boolean equals(Object obj) {
if (this == obj) {
return true; //地址相等
}
if (obj == null) {
return false; //非空性:对于任意非空引用x,x.equals(null)应该返回false。
}
if (obj instanceof Person) {
Person other = (Person) obj; //需要比较的字段相等,则这两个对象相等
if(this.name.equals(other.name)) {
return true;
}
}
return false;
}
@Override public int hashCode() {
return name.hashCode();
}
}
这不由引发了我的思考。在涉及容器是否包含某一元素的的判断中,是否是简单地遍历容器中元素并调用equal方法?重写了equal方法后能否保证两个看似等价的元素实际等价?
在搜索资料后,对这一问题我有了大致的了解。
二、hashcode方法
hashCode()方法给对象返回一个hash code值。这个方法被用于hash tables,例如HashMap。
它的性质是:
(1)在一个Java应用的执行期间,如果一个对象提供给equals做比较的信息没有被修改的话,该对象多次调用hashCode()方法,该方法必须始终如一返回同一个integer。
(2)如果两个对象根据equals(Object)方法是相等的,那么调用二者各自的hashCode()方法必须产生同一个integer结果。
(3)并不要求根据equals(java.lang.Object)方法不相等的两个对象,调用二者各自的hashCode()方法必须产生不同的integer结果。然而,程序员应该意识到对于不同的对象产生不同的integer结果,有可能会提高hash table的性能。
在进行前面比较元素是否相同的操作时,实际上是先调用了hashcode方法,若hashcode方法返回相同的值,再调用equal方法,若equal方法返回true,则两个元素相同。
三、修改
我前面出现问题的原因就是没有重写hashcode方法,导致两个equal方法返回true的元素调用hashcode方法返回的值却不同,这样在第一步判断时便会之间产生两个元素不相等的判断结果。因此除了重写equal方法外,也有必要重写hashcode方法。
将我Person类加上hashcode方法的重写。
@Override public int hashCode() {
return name.hashCode();
}
这次结果正确。