hashCode()
和equals()
及==
Java的約定-《算法4》摘錄
? 每種數(shù)據(jù)類型都需要相應(yīng)的散列函數(shù),于是Java令所有數(shù)據(jù)類型都集成了一個(gè)能夠返回一個(gè)32比特整數(shù)的hashCode()方法. 每一種數(shù)據(jù)類型的hashCode()
方法都必須和equals()
方法一致.
如果
a.equals(b)
返回true
, 那么a.hashCode()
的返回值必然和b.hashCode()
的返回值相同.如果兩個(gè)對(duì)象的
hashCode()
方法的返回值不同, 那么我們就知道這兩個(gè)對(duì)象是不同的.如果兩個(gè)對(duì)象的
hashCode()
方法的返回值相同, 這兩個(gè)對(duì)象也有可能不同, 還需要使用equals()
方法進(jìn)行判斷.-
如果要為自定義的數(shù)據(jù)類型定義散列函數(shù), 需要同時(shí)重寫
hashCode()
和equals()
方法. 默認(rèn)的散列函數(shù)會(huì)返回對(duì)象的內(nèi)容地址, 但這只適用很少的情況. Java為很多常用的數(shù)據(jù)類型重寫了hashCode()
方法(包括String擎颖、Integer、Double恳啥、File和URL
).?
==
比較符號(hào):
- 對(duì)于8中基本的數(shù)據(jù)類型, 比較的是變量所對(duì)應(yīng)內(nèi)存存儲(chǔ)的數(shù)值
- 對(duì)于指向?qū)ο蟮淖兞?/strong>, 比較的也是變量所對(duì)應(yīng)內(nèi)存存儲(chǔ)的數(shù)值(即指向的對(duì)象占用堆內(nèi)存的首地址), 也就是比較變量是否指向同一個(gè)對(duì)象.
equals()
:
-
equals
方法時(shí)用于比較兩個(gè)獨(dú)立對(duì)象的內(nèi)容是否相同, 需要為類重寫equals
方法. - 如果一個(gè)類沒有定義自己的
equals
方法, 它默認(rèn)的equals
方法就是從Object
繼承來的equals
方法, 相當(dāng)于==
操作符. 也就是在比較兩個(gè)變量指向的對(duì)象是否為同一個(gè)對(duì)象, 這時(shí)候使用equals和使用==
會(huì)得到相同的結(jié)果. 如果編寫的類希望能夠比較該類創(chuàng)建的兩個(gè)實(shí)例對(duì)象的內(nèi)容是否相同, 那么必須覆蓋equals
方法.
String
類中的equals
方法:
public boolean equals(Object anObject) {
if (this == anObject) { //如果指向的是同一個(gè)地址仔沿,那內(nèi)容肯定相同
return true;
}
if (anObject instanceof String) { // 地址不同時(shí)比較內(nèi)容是否相同
String anotherString = (String) anObject; // 判斷是否為String類
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
}
hashCode()
默認(rèn)情況下,
Object
中的hashCode()
返回對(duì)象的32位jvm地址. 也就是說如果對(duì)象不重寫該方法, 則返回相應(yīng)對(duì)象的32位jvm內(nèi)存地址.當(dāng)
equals
方法被重寫時(shí), 通常有必要重寫hashCode
方法, 以維護(hù)hashCode
方法的常規(guī)協(xié)定, 協(xié)定聲明相等對(duì)象必須具有相等的哈希碼.String
類中的hashCode
:
public int hashCode() {
int h = hash; //Default to 0 ### String類中的私有變量,
if (h == 0 && value.length > 0) { //private final char value[]; ### Sting類中保存的字符串內(nèi)容的的數(shù)組
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
-
舉例:
- 未重寫
hashCode
時(shí):
import java.util.HashMap; public class Cat { private String color; public Cat(String color) { this.color = color; } public boolean equals(Object obj) { if (obj == null) { return false; } if (!(obj instanceof Cat)) { return false; } if (this == obj) { return true; } return (this.color.equals(((Cat) obj).color)); } public static void main(String[] args) { Cat cat1 = new Cat("白色"); Cat cat2 = new Cat("黑色"); System.out.println(cat1.equals(cat2)); //false逆巍,因?yàn)橹貙懥薳quals方法及塘,且他們的顏色不一樣锐极,所以返回false。 HashMap<Cat, String> maps = new HashMap<>(); maps.put(cat1, "白色"); maps.put(cat2, "黑色"); System.out.println(maps.get(new Cat("白色"))); //null灵再,因?yàn)闆]有重寫hashcode方法肋层,所以在查找的時(shí)候計(jì)算的hashcode值不一樣翎迁,無法找到,所以返回null汪榔。 } }
對(duì)于Java中所有類的超級(jí)父類java.lang.Object而言,其hashCode()的默認(rèn)實(shí)現(xiàn)是:對(duì)于不同的對(duì)象就返回不同的整型值。上述示例代碼中全陨,Cat類沒有重寫Object的hashCode()方法爆班。所以辱姨,這條代碼System.out.println(maps.get(new Cat("白色")));創(chuàng)建的Cat類和cat1的hasncode值不一樣,所以無法找到雨涛。
- 重寫
hashCode
后
import java.util.HashMap; public class Cat { private String color; public Cat(String color) { this.color = color; } public boolean equals(Object obj) { if (obj == null) { return false; } if (!(obj instanceof Cat)) { return false; } if (this == obj) { return true; } return (this.color.equals(((Cat) obj).color)); } @Override public int hashCode() { return this.color.hashCode(); } public static void main(String[] args) { Cat cat1 = new Cat("白色"); Cat cat2 = new Cat("黑色"); System.out.println(cat1.equals(cat2)); // false HashMap<Cat, String> maps = new HashMap<>(); maps.put(cat1, "白色"); maps.put(cat2, "黑色"); System.out.println(maps.get(new Cat("白色"))); // 白色 } }
摘自: 簡(jiǎn)書.
參考: 1. ==和equals的區(qū)別
- 未重寫