JavaBean,為什么要重寫hashCode()方法和equals()方法及如何重寫
JavaBean為什么要重寫hashCode()方法和equals方法,我記得當(dāng)時(shí)我巴拉巴拉半天就是沒(méi)有說(shuō)到重點(diǎn).
現(xiàn)在想一想歸根到底還是我對(duì)這兩個(gè)的理解不深刻,現(xiàn)在我特定來(lái)總結(jié)下.hashCode 方法用于散列集合的查找,equals 方法用于判斷兩個(gè)對(duì)象是否相等。
一、我們?yōu)槭裁葱枰貙慼ashCode()方法和equals()方法?(Why)
有時(shí)在我們的業(yè)務(wù)系統(tǒng)中判斷對(duì)象時(shí)有時(shí)候需要的不是一種嚴(yán)格意義上的相等,而是一種業(yè)務(wù)上的對(duì)象相等。在這種情況下,原生的equals方法就不能滿足我們的需求了.
我們所知道的JavaBean的超類(父類)是Object類,JavaBean中的equals方法是繼承自O(shè)bject中的方法.Object類中定義的equals()方法是用來(lái)比較兩個(gè)引用所指向的對(duì)象的內(nèi)存地址是否一致.并不是比較兩個(gè)對(duì)象的屬性值是否一致,所以這時(shí)我們需要重寫equals()方法.
Object類中equals()方法的源碼
public boolean equals(Object obj) {
return (this == obj);
}
public class Demo {
public static void main(String[] args) {
Student stu1 = new Student("awu",22);
Student stu2 = new Student("awu",22);
System.out.println(stu1.equals(stu2));
/*因?yàn)镾tudent這個(gè)JavaBean沒(méi)有重寫關(guān)于屬性值相等的equals()方法
,所以默認(rèn)比較的是地址值,從而輸出結(jié)果為false*/
}
}
那么為什么在重寫equals方法的時(shí)候需要重寫hashCode方法呢?
主要是Object.hashCode的通用約定:
在java應(yīng)用程序運(yùn)行時(shí),無(wú)論何時(shí)多次調(diào)用同一個(gè)對(duì)象時(shí)的hsahCode()方法,這個(gè)對(duì)象的hashCode()方法的返回值必須是相同的一個(gè)int值. 如果兩個(gè)對(duì)象equals()返回值為true,則他們的hashCode()也必須返回相同的int值. 如果兩個(gè)對(duì)象equals()返回值為false,則他們的hashCode()返回值也必須不同.
以HashSet來(lái)說(shuō)明為什么要這么約定:HashSet存放元素時(shí),根據(jù)元素的hashCode值快速找到要存儲(chǔ)的位置,如果這個(gè)位置有元素,兩個(gè)對(duì)象通過(guò)equals()比較,如果返回值為true,則不放入;如果返回值為false,則這個(gè)時(shí)候會(huì)以鏈表的形式在同一個(gè)位置上存放兩個(gè)元素,這會(huì)使得HashSet的性能降低,因?yàn)椴荒芸焖俣ㄎ涣恕?/p>
還有一種情況就是兩個(gè)對(duì)象的hashCode()返回值不同,但是equals()返回true,這個(gè)時(shí)候HashSet會(huì)把這兩個(gè)對(duì)象都存進(jìn)去,這就和Set集合不重復(fù)的規(guī)則相悖了;所以,我們重寫了equals()方法時(shí),要按照b,c規(guī)則重寫hashCode()方法!(其實(shí)就是如果只重寫了 equals 方法,兩個(gè)對(duì)象 equals 返回了true,但是如果沒(méi)有重寫 hashCode 方法,集合還是會(huì)插入元素。這樣集合中就出現(xiàn)了重復(fù)元素了。)
二、在什么情況下需要重寫hashCode()方法和equals()方法? (When)
當(dāng)我們自定義的一個(gè)類,想要把它的實(shí)例保存在以Hash散列查找的集合中時(shí),我們就需要重寫這兩個(gè)方法;
public class Student {
private String name;
private Integer age;
public Student(){
}
public Student(String name,Integer age){
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public int hashCode(){
final int prime = 31;
int result = 17;
result = prime * result + name.hashCode();
result = prime * result + age;
return result;
}
@Override
public boolean equals(Object obj){
if(this == obj)
return true;
if(obj == null)
return false;
if(getClass() != obj.getClass())
return false;
final Student other = (Student)obj;
if(name.equals(other.name)){
return false;
}
if(age.equals(other.age)){
return false;
}
return true;
}
}
public class Demo {
public static void main(String[] args) {
Student stu1 = new Student("awu",22);
Student stu3 = new Student("awu",33);
Student stu2 = new Student("awu",22);
Set set = new HashSet();
set.add(stu1);
set.add(stu2);
set.add(stu3);
System.out.println(set.size());
/*輸出結(jié)果為2*/
}
}
如果不是以Hash散列查找的集合,即使重寫HashCode也沒(méi)多大實(shí)際用處.比如如下栗子:
public class Demo {
public static void main(String[] args) {
Student stu1 = new Student("awu",22);
Student stu3 = new Student("awu",33);
Student stu2 = new Student("awu",22);
ArrayList list = new ArrayList();
list.add(stu1);
list.add(stu2);
list.add(stu3);
System.out.println(list .size());
/*輸出結(jié)果為3*/
}
}
三、如何重寫這兩個(gè)方法?(How)
public class Student {
private String name;
private Integer age;
public Student(){
}
public Student(String name,Integer age){
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public int hashCode(){
final int prime = 31;
int result = 17;
result = prime * result + name.hashCode();
result = prime * result + age;
return result;
}
@Override
public boolean equals(Object obj){
if(this == obj)
return true;
if(obj == null)
return false;
if(getClass() != obj.getClass())
return false;
final Student other = (Student)obj;
if(name.equals(other.name)){
return false;
}
if(age.equals(other.age)){
return false;
}
return true;
}
}
