1.Java中==、equals、hashCode的區(qū)別?
1.1基本數(shù)據(jù)類型使用==與equals
- java基本數(shù)據(jù)類型包括:byte、short、int、long、float、double、boolean、char
- 基本數(shù)據(jù)類型使用"=="比較內(nèi)容是否相同,不能使用equals
int d = 2;
int e = 3;
int f = 3;
System.out.println(d == e);//2與3比較
System.out.println(e==f);//3與3比較
//System.out.println(d.equals(f));基本數(shù)據(jù)類型中沒有equals方法
false
true
1.2引用數(shù)據(jù)類型==與equals
- 引用數(shù)據(jù)類型使用"=="比較棧內(nèi)存地址是否相同
String g = new String("aw1");
String h = new String("aw");
String i = new String("aw");
System.out.println(g==h);//對象g的地址與對象h的地址比較
System.out.println(h==i);//對象h的地址與對象i的地址比較
false
false
- 引用數(shù)據(jù)類型使用equals先比較對象類型是否相同,再比較堆中對象的內(nèi)容是否相同。
System.out.println(h.equals(i));//對象h的內(nèi)容aw與對象i的內(nèi)容aw比較
System.out.println(h.equals(g));///對象h的內(nèi)容aw與對象g的內(nèi)容aw1比較
true
false
- 小坑:
- 包裝類型使用"=="與上述說的有些不一樣,從源碼可看出,包裝類型的值如果在范圍內(nèi),會進行緩存,后面需要使用該對象,直接可以從緩存中取,不會再new對象。但在范圍之外,會在堆上產(chǎn)生新對象,并不會復(fù)用已有對象。包裝類型使用equals與引用數(shù)據(jù)類型一樣。
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
Integer ina = 1;
Integer inb = 1;
Integer inc = 1000;
Integer ind = 1000;
System.out.println(ina == inb);//在-128~127范圍內(nèi),b直接從緩存中取,地址一樣
System.out.println(inc == ind);//超過127,會產(chǎn)生新對象d,地址不一樣
System.out.println(ina.equals(inb));//equals之比較類型和對應(yīng)內(nèi)容是否一樣,1與1
System.out.println(inc.equals(ind));//1000與1000
true
false
true
true
1.3hashCode
??Java中的集合(Collection)有兩類,一類是List,再有一類是Set。前者集合內(nèi)的元素是有序的,元素可以重復(fù);后者元素?zé)o序,但元素不可重復(fù)。判斷元素是否重復(fù)使用Object.equals方法,但是每增加一個元素,就需要遍歷整個集合,效率會很低。
??于是,Java采用了哈希表的原理,當(dāng)集合要添加新的元素時,先調(diào)用這個元素的hashCode方法,就能定位到它應(yīng)該放置的哈希表中對應(yīng)位置。 如果這個位置上沒有元素,它就可以直接存儲在這個位置上,不用再進行任何比較了;如果這個位置上已經(jīng)有元素了,就調(diào)用它的equals方法與新元素進行比較,相同的話就不存,不相同就散列其它的地址。這樣一來實際調(diào)用equals方法的次數(shù)就大大降低了。
- 基本類型包裝類hashCode的方法實現(xiàn)
https://blog.csdn.net/realwongp/article/details/88901418
2.為什么要重寫equals還要重寫hashCode?
在HashMap中,如果要比較key值是否相等,要同時使用equals和hashCode,因為自定義類的hashCode方法繼承于Object類,hashCode碼為默認的內(nèi)存地址,這樣即便有相同含義的兩個對象,比較也是不同的。
HashMap中比較key值是先求出key的hashCode碼,比較其值是否相等。若相等,再比較equals(),若為true則認為是相等的,若為false則認為是不相等的。如果只重寫的hashCode()方法,不重寫equals()方法,那么只是對它們內(nèi)存地址的比較,所以要兩個方法一起重寫。
關(guān)于hashCode方法,一致的約定是:
??1.重寫了euqals方法的對象必須同時重寫hashCode()方法。
??2.如果2個對象通過equals調(diào)用后返回是true,那么這個2個對象的hashCode方法也必須返回同樣的int型散列碼
??3.如果2個對象通過equals返回false,他們的hashCode返回的值允許相同,最好是不相同。以下為Student類,只重寫了hashCode(),沒有重寫equals(),雖然s1與s2內(nèi)容相同且hashCode相同,但是equals()比較的是s1與s2內(nèi)存地址是否一樣,所以返回了false。如上約定3所言。
public class Student {
public String name;
public int age;
public double weight;
public boolean isMarry;
public Student(String name, int age, double weight, boolean isMarry){
this.name = name;
this.age = age;
this.weight = weight;
this.isMarry = isMarry;
}
@Override
public int hashCode(){
int result = name != null ? name.hashCode():0;
result = 31*result + age % 10;
Long temp = Double.doubleToLongBits(this.weight);
result = 31*result + (int)(temp ^ (temp >>>32));
result = 31*result + (isMarry ? 1:0);
return result;
}
public static void main(String[] args) {
Student s1 = new Student("hihi",2,52.5,true);
Student s2 = new Student("hihi",2,52.5,true);
Student s3 = new Student("hihisas",4,52.5,false);
System.out.println(s1.hashCode());
System.out.println(s2.hashCode());
System.out.println(s3.hashCode());
System.out.println(s1.equals(s2));
System.out.println(s2.equals(s3));
}
-6555007
-6555007
-2036969151
false
false
- 重寫equals()后,如上約定2所言,equals返回的是true,那么兩個對應(yīng)的hashCode值必須相等。
@Override
public boolean equals(Object object) {
Student student = (Student) object;
if(student == null ){
return false;
}else if(this.name==student.name&&this.age==student.age&&this.isMarry==student.isMarry&&this.weight==student.weight){
return true;
}
return false;
}
-6555007
-6555007
-2036969151
true
false
以上僅為學(xué)習(xí)筆記,如有錯誤,請多指教!