Java中的equals 和hashCode的理解
阿新 • • 發佈:2018-11-09
前幾天面試,被問了一個hashCode值相等,物件是否相等;物件相等,hashCode是否相等。
突然懵逼了,因為是面試,一下緊張,按照記憶中的說的,完全打錯,結果可想而知。 可見自己對這完全不理解,故重新認識一番。
Java對於eqauls方法和hashCode方法是這樣規定的:
1、如果兩個物件相同,那麼它們的hashCode值一定要相同;
2、如果兩個物件的hashCode相同,它們並不一定相同(上面說的物件相同指的是用eqauls方法比較。)
物件預設都extends Object ,先看Object對這兩個方法的定義:
是不是突然懵逼了,這明明比較物件的記憶體地址是否相等,也就是判斷是不是同一個物件。但是為什麼很多情況下都會用equals()去比較內容是否一致呢?public boolean equals(Object obj) { return (this == obj); }
然後開啟String類的原始碼,會發現:
會發現,這種情況下,是String重寫了Object類的equals(),有了自己的實現方式,所以平常我們判斷字串內容是否相等用equals()是正確的。而且不止String類重寫了,Double、Float也都重寫了。public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String anotherString = (String) anObject; 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()且看Object類中對它的定義:
public native int hashCode();
可以看到這是一個本地方法,返回的物件的地址值。
而再次拿出String類中的hashCode()方法:
最終也是返回一個計算出的hash值,用於判斷。public int hashCode() { int h = hash; if (h == 0 && value.length > 0) { char val[] = value; for (int i = 0; i < value.length; i++) { h = 31 * h + val[i]; } hash = h; } return h; }
Java中的集合(Collection)有兩類,一類是List,再有一類是Set。 前者集合內的元素是有序的,元素可以重複;後者元素無序,但元素不可重複。
當集合要新增新的元素時,先呼叫這個元素的hashCode方法,就一下子能定位到它應該放置的物理位置上。 如果這個位置上沒有元素,它就可以直接儲存在這個位置上,不用再進行任何比較了;如果這個位置上已經有元素了, 就呼叫它的equals方法與新元素進行比較,相同的話就不存了,不相同就雜湊其它的地址。
public class Test01 {
public static void main(String[] args) {
Name name1 = new Name("24");
Name name2 = new Name("24");
Set set = new HashSet();
set.add(name1);
System.out.println("********************111");
set.add(name2);
System.out.println("********************222");
System.out.println(name1.equals(name2));
System.out.println("********************333");
System.out.println(name1.hashCode());
System.out.println(name2.hashCode());
System.out.println(set);
}
}
class Name {
private String id;
public Name(String id) {
this.id = id;
}
public String toString() {
return this.id;
}
public boolean equals(Object obj) {
if(obj instanceof Name) {
Name name = (Name) obj;
System.out.println("equals:"+name.id);
return (id.equals(name.id));
}
return super.equals(obj);
}
public int hashCode() {
Name name = (Name) this;
System.out.println("Hash:"+name.id);
return id.hashCode();
}
}
執行結果如下:
public class Test01 {
public static void main(String[] args) {
Name name1 = new Name("24");
Name name2 = new Name("24");
List list = new ArrayList();
list.add(name1);
System.out.println("********************111");
list.add(name2);
System.out.println("********************222");
System.out.println(name1.equals(name2));
System.out.println("********************333");
System.out.println(name1.hashCode());
System.out.println(name2.hashCode());
System.out.println(list);
}
}
執行結果如下:
可以看出,set進行新增的時候,先去判斷hashCode,而list就不必判斷hashCode,它可以儲存重複資料,而set判斷後,如果有相同值,不進行儲存。
總結,這些在學校都是最基礎的東西,可惜當初沒認真聽,後來也是覺得該怎麼用就怎麼用,也沒去思考一些最基本的東西,所以,還是要多理解。