参考文献:
看似简单的hashCode和equals面试题,竟然有这么多坑!
q: 定义了student类,有age属性,然后a=new Student(10);b=new Student(10),现在有a==b,a.equals(b)则分别输出什么?
答:==是算述运算符,可以比较基本数据类型,也可以比较引用数据类型,如果比较的是基本数据类型比较的是值相等,如果比较的是引用数据类型,比较的是地址值是否相等。Equals默认比较的是地址值,具体怎样比较需要根据自己的要求进行自定义的比较方式。a==b输出false,a.equals(b)在自定义的类Student重写equals方法时如果重写了age属性则输出true,如果没有重写age属性,则为false;(注意:如果是java中继承了Object类的,已经重写过了Object中的equals()方法,则使用equals比较时就是输出true)。
import java.util.*;
class Student{
String name;
int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age && Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
public class Main {
public static void main(String[] args) {
Student s1=new Student("mingming",12);
Student s2=new Student("mingming",12);
/*
和equals()一样,Object里hashCode()里面只是返回当前对象的地址,
如果是这样的话,那么我们相同的一个类,new两个对象,
由于他们在内存里的地址不同,则他们的hashCode()不同且equals=false
因此可以同时放到hashset
*/
System.out.println(s1.hashCode()+" "+s2.hashCode());
System.out.println(s1.equals(s2));//false
HashSet<Student> set = new HashSet<>();
set.add(s1);
set.add(s2);
System.out.println(set.size());//2
}
}
结果输出:
1.不重写equals和hascode的结果:
2083562754 1239731077
false
2
2.只重写equals的结果
2083562754 1239731077
true
2
3.重写equals和hascode之后的结果:
761311971 761311971
true
1
结论:
所以如果我们的对象要想放进hashSet,并且发挥hashSet的特性(即不包含一样的对象),则我们就要重写我们类的hashCode()和equals()方法了。像String,Integer等这种类内部都已经重写了这两个方法。
当然如果我们只是平时想对比两个对象 是否一致,则只重写一个equals(),然后利用equals()去对比也行的。
hascode相等,equals一定相等
重写equals+hascode equals为true ,hascode相等
只重写equals equals为true ,hascode不一定相等
应用:
hash容器中,比如HashSet,HashMap,HashTable等等,要求对象不能重复,添加新的对象要进行对比
问题1、equals()既然已经能实现对比的功能了,为什么还要hashCode()呢?
因为重写的equals()里一般比较的比较全面比较复杂,这样效率就比较低,而利用hashCode()进行对比,则只要生成一个hash值进行比较就可以了,效率很高。
问题2、hashCode()既然效率这么高为什么还要equals()呢?
因为hashCode()并不是完全可靠,有时候不同的对象他们生成的hashcode也会一样(生成hash值得公式可能存在的问题),所以hashCode()只能说是大部分时候可靠,并不是绝对可靠,所以我们可以得出(PS:以下两条结论是重点,很多人面试的时候都说不出来):
问题3:为什么要重写hascode()
避免出现,两个对象明明是相等(equals()=true),而hashCode却不一样。 如上的结果2.
2083562754 1239731077
true
2造成的结果就是:
当你用其中的一个作为键保存到hashMap、hasoTable或hashSet中,再以“相等的”找另一个作为键值去查找他们的时候,则根本找不到。
问题4:什么时候需要重写hascode()
一般的地方不需要重载hashCode,只有当类需要放在HashTable、HashMap、HashSet等等hash结构的集合时才会重载hashCode。
阿里巴巴开发规范也明确规定: