1.为什么要重写equals()?
因为我们在用equals()来比较两个对象时,默认是用==来比较,比较的是两个对象的地址,所以如果我们想通过比较两个对象的值来确定两个对象是否相同,则需要重写equals()。
Object.class中的源码:
* @param obj the reference object with which to compare.
* @return {@code true} if this object is the same as the obj
* argument; {@code false} otherwise.
* @see #hashCode()
* @see java.util.HashMap
*/
public boolean equals(Object obj) {
return (this == obj);
}
2.为什么在重写equals()时也要重写hashCode()?
当重写equals()方法是,一般都要重写hashCode(),因为在维护hashCode()方法的常规协定中声明了相等对象必须具有相等的哈希码,具体如下:
(1)当obj1.equals(obj2)为true时,obj1.hashCode() == obj2.hashCode()必须为true
(2)当obj1.hashCode() == obj2.hashCode()为false时,obj1.equals(obj2)必须为false
另外hashCode是用于散列数据的快速存取(如在利用HashSet、HashMap、HashTable类来存储数据时,都是利用hashCode值来判断对象是否相同),如果只对equals()进行了重写,而不对hashCode()进行重写,那么就可能出现一些问题,如在用HashSet类来存储数据时,如果只重写了equals(),而没有重写hashCode(),就可能出现obj1.equals(obj2)为true,但是hashCode却是不一样的情况,此时将会存储两个值一样的对象 ,这时就和HashSet类中只能存储不重复的对象产生了冲突。
3.重写equals()和hashCode()的简单示例
(1)User类中重写equals()和hashCode()
public class User {
private String name;
private int age;
public User() {
super();
}
public User(String name, int age) {
super();
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 obj) {
// 首先判断该对象是否为空
if (obj == null) {
return false;
}
// 判断两个比较对象是否为同一个类
// Object.getClass() 返回的是此Object的执行类,此处也可以用instanceof来比较
if (this.getClass() != obj.getClass()) {
return false;
}
// 把obj对象强制转化为User对象
User otherObj = (User) obj;
return this.getName().equals(otherObj.getName()) && this.getAge() == this.getAge();
}
// 选用31和17是一种默认的做法,可以在一定程度上有效的避免hashcode的重复
@Override
public int hashCode() {
int result = 17;
result = 31 * result + name.hashCode();
result = 31 * result + age;
return result;
}
}
(2)测试