我们都知道在比较两个对象相同时需要重写equals()方法以确保两个对象内容相同时就是相等的对象。那么是否有必要重写hashcode()方法呢?请看代码:
1.我们先看一段完整的代码
import java.util.HashSet;
public class Code {
public static void main(String[] args) {
Person p1=new Person("张三",16);
Person p2=new Person("张三",16);
Person p3=new Person("李四",20);
HashSet<Person> list=new HashSet<>();
list.add(p1);
list.add(p2);
list.add(p3);
System.out.println(list);
}
}
class Person{
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
if (age != person.age) return false;
return name != null ? name.equals(person.name) : person.name == null;
}
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + age;
return result;
}
}
结果:
2.如果把重写的hashcode()注释掉
结果:
我们发现hashset集合里有相同的对象,这是因为set集合存储元素默认是按照哈希吗的不同来存储的,而不是内容。
3.如果再把tostring()方法注释掉
结果:
我们发现两个对象即使内容相同而哈希吗不同,也会被set集合以哈希吗来存储。
4.我们再来回顾一下重写的hashcode()方法
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + age;
return result;
}
关键是第三行代码。它以name的哈希值为基础进行计算,也就是对象的哈希值是取决于name的哈希值。而对于字符串来说,只要不是new出来的,那么如果两个字符串内容相同的话,他们会指向同一个地址,所以他们的哈希值是相同的。
JDK API中如此描述:
总结:如果不用set集合去重,如果只是单纯比较两个内容一样的对象,那么是可以不用重新hashcode()方法的。因为我们只会调用equals()方法。不过最好还是重新hashcode()方法,因为判断两个对象是否相同时会先判断哈希值是否相同,如果哈希值不同,就不用再比较了。如果哈希值相同,就要比较equals()方法,如果返回true,那么此时称两个对象哈希冲突。因此重写hashcode()会优化程序及提高效率。