本篇没有理论,只有实践,通过实例清晰让你了解为什么要这样做。
任务:
- 建立(学生----父亲姓名)关系
- 必须使用HashMap并且key为学生,value为父亲姓名
- 建立学生类:
public class Student {
//学号唯一
public int num;
public Student(int num) {
this.num = num;
}
}
- 开始测试
Student s1 = new Student(520);
Student s2 = new Student(520);
System.out.println(s1.equals(s2));//输出false
- 学号一样,我们就认为是同一个学生,
但是由于是new了两个对象所以必定为 false,
所以我们需要重写Student的equals方法,改变判断逻辑
public class Student {
//学号唯一
public int num;
public Student(int num) {
this.num = num;
}
@Override
public boolean equals(Object obj) {
if (this == obj){//如果引用地址相同必定是同一个学生
return true;
}
if (obj instanceof Student){
Student stu = (Student) obj;
if (num == stu.num){//如果学号相同我们也认为是同一个学生
return true;
}
}
return false;
}
}
- 此时使用equals进行比较就是true,符合我们的逻辑:学号相同必定是同一个学生,即s1和s2为同一个人
Student s1 = new Student(520);
Student s2 = new Student(520);
System.out.println(s1.equals(s2));//输出true
- 这里我们只重写了equals方法没有重写hashCode方法,
接着我们使用HashMap来建立(学生----父亲姓名)关系
Student s1 = new Student(520);
Student s2 = new Student(520);
Map<Student, String> map = new HashMap<>();
map.put(s1,"小明");
map.put(s2,"小刚");
System.out.println(map.get(s1));//输出小明
System.out.println(map.get(s2));//输出小刚
-
我们由上一步得出s1和s2为同一个人,但我们分别put后,第一次put的值并没有被第二次覆盖,也就是HashMap的去重失效了。
也就是学号为520的同学竟然有两个亲生父亲,分别为小明和小刚,这显然是不符合逻辑的。 -
造成HashMap去重失效的原因正是由于没有重写hashCode方法,HashMap进行put的时候会根据key的hashCode进行一系列运算得出value的存储位置,如果两个计算的位置一样则会调用equals继续比较,如果还是一样则会覆盖,否则就另外找一个地方存储。(把大概意思讲一下,具体请看HashMap源码)。
-
重写hashCode
public class Student {
//学号唯一
public int num;
public Student(int num) {
this.num = num;
}
@Override
public boolean equals(Object obj) {
if (this == obj){//如果引用地址相同必定是同一个学生
return true;
}
if (obj instanceof Student){
Student stu = (Student) obj;
if (num == stu.num){//如果学号相同我们也认为是同一个学生
return true;
}
}
return false;
}
@Override
public int hashCode() {
//获取学号的hash作为自身的hash
return Integer.valueOf(num).hashCode();
}
}
- 再进行测试
Student s1 = new Student(520);
Student s2 = new Student(520);
Map<Student, String> map = new HashMap<>();
map.put(s1,"小明");
map.put(s2,"小刚");
System.out.println(map.get(s1));//输出小刚
System.out.println(map.get(s2));//输出小刚
- 此时输出的是小刚和小刚
只重写equals而不重写hashCode会导致一些底层使用hash作为判断的类一些功能失效。String重写了equals和hashCode方法所以String可以作为HashMap的key。