首先我们来看java中对Object的规范:
- 在应用程序的执行期间,只要对象的equals方法的比较操作所用到的信息没有被修改,那么对同一个对象的多次调用,hashCode方法都必须始终返回同一个值。在一个应用程序与另一个程序的执行过程中,执行 hashcode 方法所返回的值可以不一致。
- 如果两个对象根据equals(Object)方法比较是相等的,那么调用这两个对象中的hashCode 方法都必须产生同样的整数结果。
- 如果两个对象根据equals(Object)方法比较是不相等的,那么调用这两个对象中的hashCode 方法,则不一定要求hashCode方法必须产生不同的结果。但是程序员应该知道,给不相等的对象产生截然不同的整数结果,有可能提高散列表(hash table)的性能。
如果没有重写hashCode方法就会违反第二条规定:相等的对象必须具有相等的散列码(hashCode)
我们创建一个Student类,重写equals方法,不重写hashCode方法
public class Student {
int age;
String name;
public Student(int age, String name) {
this.age = age;
this.name = name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Student)) return false;
Student student = (Student) o;
return age == student.age &&
Objects.equals(name, student.name);
}
}
在main函数中创建两个逻辑上相同的student对象,使用刚才重写的equals方法比较,并使用Object类中的hashCode方法分别生成hashCode
public class Test {
public static void main(String[] args) {
Student s1 = new Student(19,"ZZY");
Student s2 = new Student(19,"ZZY");
System.out.println(s1.equals(s2));
System.out.println(s1.hashCode());
System.out.println(s2.hashCode());
}
}
打印结果如下:
可以看到,这两个对象逻辑上是相同的,调用重写equals方法返回true,但是它们的散列码却不相同,原因在于如果根据Object类中的hashCode方法,这两个对象仅仅是两个没有任何共同之处的对象,hashCode返回的是两个看起来随机的整数,违反了开头Object规范中的第二条。
接下来我们使用idea自动重写hashCode方法(调用Object中的hash方法)
@Override
public int hashCode() {
return Objects.hash(age, name);
}
}
重新执行main函数里面的代码,打印结果如下: 可以看到此时两者的hashCode是相同的了,满足了第二条规范(相等的对象必须具有相等的散列码) 注意: 调用Object中的hash方法来重写hashCode方法运行速度会慢一些,因为为了传入可变的参数要引起数组的创建,如果参数里面有基本类型,还需要装箱和拆箱。 下面是不使用hash方法重写hashCode的方法:
@Override
public int hashCode() {
int result = Integer.hashCode(age);
result = 31 * result + name.hashCode();
return result;
}
总结: 总而言之,每当覆盖equals方法时都必须覆盖hashCode,否则程序将无法正确运行。hashCode方法必须遵守Object规定的通用约定,并且必须完成一定的工作,将不相等的散列码分配给不相等的实例
|