hashCode
hashCode()的作用时获取哈希码,也成为数列码,它实际上是返回一个int整数,这个哈希码的作用是确定该对象再哈希表中的索引位置。hashCode()定义在JDK的Object.java中,java中的任何类都包含有hashCode()函数。散列表存储的是键值对(key-value)。他的特点是:能根据“键”快速的检索出对应的“值”。这其中就利用到了散列码(可以快速找到所需要的对象)
为什么要有hashCode
以“HashSet如何检查重复”为例子来说明为什么要有hashCode:
对象加入HashSet时,HashSet会先计算对象的hashcode值来判断对象加入的位置,看该位置是否有值,如果没有,HashSet会假设对象没有重复出现,但是如果发现有值,这时会调用equals()方法来检查两个对象是否真的相同。如果两者相同,HashSet就不会让其加入操作成功。如果不同的话,就会重新散列到其他的位置,这样就大大减少了equals的次数,相应就大大提高了执行速度。
- 如果两个对象相等,则hashcode一定也是相同的
- 两个对象相等,对两个对象分别调用equals方法都返回true
- 两个相同的hashcode值,他们也不一定是相等的
- 因此,equls方法被覆盖过,则hashCode方法必须被覆盖
- hashcode()的默认行为是对堆上的对象产生独特值。如果没有重写hashCode(),则该class的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)
举例:当自定义对象并调用equals方法没有重写hashCode()和equals()方法时
创建一个Student类:
//创建一个Student类
//此时并没有重写hashcode和equals方法
public class Student {
String name;
int age;
public Student() {
}
public Student(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;
}
}
测试代码:
public class Test {
public static void main(String[] args){
//创建两个Student对象
Student student1=new Student("张三",18);
Student student2=new Student("张三",18);
//此时并没有重写hashcode和equals方法
//当直接调用student1和student2的hashcode方法时
System.out.println(student1.hashCode());
System.out.println(student2.hashCode());
System.out.println(student1.equals(student2));
}
}
测试结果:
实际上我们的逻辑是希望这两个student1和student2的对象应该是相等的,因为他们的name和age属性都是“张三”和18,但是在没有重写hashcode()和equals两个方法的时候这两个对象产生的hashcode的值都不一样,而且调用的equals方法则是下图所示
那么此时这两个student1和student2的内存首地址都不一样,当然这个return this==obj;返回的肯定就是false了。
在Student类中重写hashCode()和equals方法后,即如下所示
//创建一个Student类
//此时并没有重写hashcode和equals方法
public class Student {
String name;
int age;
public Student() {
}
public Student(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;
}
//重写equals方法
@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);
}
//重写hashCode方法
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
测试结果:
那么将重写的equals方法和hashCode方法其中一个方法删除掉又会出现什么样的结果呢?
1.删除掉equals方法
这就验证了前面的说法:两个相同的hashcode值,他们也不一定是相等的
2.删除掉hashcode方法
这就和前面的说法有矛盾了:如果两个对象相等,则hashcode一定也是相同的,因此,equls方法被覆盖过,则hashCode方法必须被覆盖
总结
equals方法和hashCode()方法也必须要同时重写