为什么要重写hashcode()和equals()方法
在这之前先看一段代码
Person.java
public class Person {
private int id;
private String name;
private double salary;
private long account;
public Person(int id, String name, double salary, long account) {
super();
this.id = id;
this.name = name;
this.salary = salary;
this.account = account;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public long getAccount() {
return account;
}
public void setAccount(long account) {
this.account = account;
}
}
Test.java
public class Test {
public static void main(String[] args) {
Person person=new Person(1, "jim", 1000, 1000000);
Person jim=new Person(1, "jim", 1000, 1000000);
if(person.equals(jim)) {
System.out.println("true");
}else {
System.out.println("false");
}
}
}
最终程序运行的结果为false,这是为什么呢,其实也很好理解,因为在java中,每new一个对象就会给他分配到堆区,一般在栈区存储一个引用变量
指向这个堆区的内存空间,main方法中new了两个Person对象,那么这两个对象的在堆区的内存空间是不一样的,即使这两个对象的所有属性都相同,编译
器也不认为这两个对象其实是同一个对象,这有违现实生活的常理,如果两个人的身份证号,姓名完全相同,我们就认为他们是同一个人,事实上只需要身份
证相同就够了,那么如何做到让java语言也能实现这样的功能呢,这个时候需要我们重写equals()方法,那么怎么重写呢?
前者对象叫person,后者叫jim
1.首先,如果这个对象就是和它比较的对象分配在同一块堆区,那么这两个对象相等,
2.如果这个比较的对象不为空,那么利用反射机制获取这个对象的类是不是和被比较的对象一致
3.如果不一致,则无法比较,说明两个对象不相等
4.如果一致,则要比较这两个对象的所有属性是否完全一致,一旦有一个不一致,则两对象不相等
5,只有满足上面所有的条件后才能说明两个对象相等。
具体方法就是在javabean中重写java.lang.Object下的equals方法。
也就是在Person.java中重写equals()方法,添加代码如下
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
if (account != other.account)
return false;
if (id != other.id)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (Double.doubleToLongBits(salary) != Double.doubleToLongBits(other.salary))
return false;
return true;
}
这个时候发现打印的结果为true,说明两个对象相等了,但是,还是有一个问题存在,我们重写的equals()方法仅仅只是让equals()方法认为两个
对象相等,事实上真的相等吗,其实不相等,因为堆区实际上还是存在两个对象person和jim,他们的内存空间仍然不同,这就和java语言的原理不一
致了,因为分配到堆区的内存空间实际上是hashcode()方法决定的,如果两个对象相等但hashcode却不同,也会给人一种误会,所以重写hashcode()
实际上是让编译器也认为两个对象相等,而不是我们一厢情愿的认为,事实上你可以通过重写equals()来达到不相等的两个对象返回值为true,上面就是一
个实际的例子,那么来看一下重写hashcode()的代码。
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) (account ^ (account >>> 32));
result = prime * result + id;
result = prime * result + ((name == null) ? 0 : name.hashCode());
long temp;
temp = Double.doubleToLongBits(salary);
result = prime * result + (int) (temp ^ (temp >>> 32));
return result;
}
简单介绍一下hashcode()的原理
把某个非零常数值,例如17或者31(有兴趣可以百度一下为什么是这两个整数),保存在int型变量result中。
对于对象中每一个关键域f(指equals方法中考虑的每一个域)参照以下原则处理。
boolean型,计算(f ? 0:1)。
byte、char和short型,计算(int)。
long 型,计算(int)(f^(f>>>32))。
float 型,计算Float.floatToIntBits(afloat)。
double型,计算Double.doubleToLongBits(adouble)得到一个long,再执行long型的处理。
对象引用,递归调用它的hashCode()方法。
数组域,对其中每个元素调用它的hashCode()方法。
将上面计算得到的散列码保存到int型变量c,然后执行result=37×result+c。
返回result。
怎么重写hashcode()和equals()方法
事实上重写hashcode()和equals()方法是非常简单的,基本编译器都会自带生成hashcode()和equals()方法只需要鼠标轻轻一点就可以了,eclipse
中是在source中,或者alt+shift+s,一般建议重写equals()方法时顺便重写hashcode(),如果是编译器自动生成则两个都被重写,在Set中时,因为Set
不能存储重复的元素,所以就涉及到了判断对象是否相等,如果只重写equals()方法而不重写hashcode()方法,那么根据hashcode值确定对象是否相等
的Set就会存储两个hashcode不同的但实际上相等的两个对象。
本文探讨了在JavaBean中重写hashcode()和equals()方法的重要性,通过示例代码展示了如何进行重写,以确保对象比较的一致性和哈希表操作的正确性。


被折叠的 条评论
为什么被折叠?



