HashCode和equal方法
equals()反映的是對象或變量具體的值,即兩個對象里面包含的值--可能是對象的引用,也可能是值類型的值。
而hashCode()是對象或變量通過哈希算法計算出的哈希值。
之所以有hashCode方法,是因為在批量的對象比較中,hashCode要比equals來得快,很多集合都用到了hashCode,比如HashTable。
?
兩個obj,如果equals()相等,hashCode()一定相等。
兩個obj,如果hashCode()相等,equals()不一定相等(Hash散列值有沖突的情況,雖然概率很低)。
所以:
可以考慮在集合中,判斷兩個對象是否相等的規則是:
第一步,如果hashCode()相等,則查看第二步,否則不相等;
第二步,查看equals()是否相等,如果相等,則兩obj相等,否則還是不相等。
?
1、首先equals()和hashcode()這兩個方法都是從object類中繼承過來的。
equals()是對兩個對象的地址值進行的比較(即比較引用是否相同)。
hashCode()是一個本地方法,它的實現是根據本地機器相關的。
2、Java語言對equals()的要求如下,這些要求是必須遵循的:
A 對稱性:如果x.equals(y)返回是“true”,那么y.equals(x)也應該返回是“true”。
B 反射性:x.equals(x)必須返回是“true”。
C 類推性:如果x.equals(y)返回是“true”,而且y.equals(z)返回是“true”,那么z.equals(x)也應該返回是“true”。
D 一致性:如果x.equals(y)返回是“true”,只要x和y內容一直不變,不管你重復x.equals(y)多少次,返回都是“true”。
任何情況下,x.equals(null),永遠返回是“false”;x.equals(和x不同類型的對象)永遠返回是“false”。
3、equals()相等的兩個對象,hashcode()一定相等;
反過來:hashcode()不等,一定能推出equals()也不等;
hashcode()相等,equals()可能相等,也可能不等。?
?
引用:http://blog.sina.com.cn/s/blog_59e0c16f0100xne7.html
1、為什么要重載equal方法?
答案:因為Object的equal方法默認是兩個對象的引用的比較,意思就是指向同一內存,地址則相等,否則不相等;如果你現在需要利用對象里面的值來判斷是否相等,則重載equal方法。
2、 為什么重載hashCode方法?
答案:一般的地方不需要重載hashCode,只有當類需要放在HashTable、HashMap、HashSet等等hash結構的集合時才會重載hashCode,那么為什么要重載hashCode呢?就HashMap來說,好比HashMap就是一個大內存塊,里面有很多小內存塊,小內存塊里面是一系列的對象,可以利用hashCode來查找小內存塊hashCode%size(小內存塊數量),所以當equal相等時,hashCode必須相等,而且如果是object對象,必須重載hashCode和equal方法。
3、 為什么equals()相等,hashCode就一定要相等,而hashCode相等,卻不要求equals相等?
答案:1、因為是按照hashCode來訪問小內存塊,所以hashCode必須相等。
2、HashMap獲取一個對象是比較key的hashCode相等和equal為true。
之所以hashCode相等,卻可以equal不等,就比如ObjectA和ObjectB他們都有屬性name,那么hashCode都以name計算,所以hashCode一樣,但是兩個對象屬于不同類型,所以equal為false。
4、 為什么需要hashCode?
1、 通過hashCode可以很快的查到小內存塊。
2、通過hashCode比較比equal方法快,當get時先比較hashCode,如果hashCode不同,直接返回false。
?
hashCode()的作用
1.hashcode是用來查找的,如果你學過數據結構就應該知道,在查找和排序這一章有
例如內存中有這樣的位置
0???? 1???? 2???? 3???? 4???? 5???? 6???? 7????
而我有個類,這個類有個字段叫ID,我要把這個類存放在以上8個位置之一,如果不用hashcode而任意存放,那么當查找時就需要到這八個位置里挨個去找,或者用二分法一類的算法。
但如果用hashcode那就會使效率提高很多。
我們這個類中有個字段叫ID,那么我們就定義我們的hashcode為ID%8,然后把我們的類存放在取得得余數那個位置。比如我們的ID為9,9除8的余數為1,那么我們就把該類存在1這個位置,如果ID是13,求得的余數是5,那么我們就把該類放在5這個位置。這樣,以后在查找該類時就可以通過ID除8求余數直接找到存放的位置了。
2.但是如果兩個類有相同的hashcode怎么辦那(我們假設上面的類的ID不是唯一的),例如9除以8和17除以8的余數都是1,那么這是不是合法的,回答是:可以這樣。那么如何判斷呢?在這個時候就需要定義?? equals了。
也就是說,我們先通過?? hashcode來判斷兩個類是否存放某個桶里,但這個桶里可能有很多類,那么我們就需要再通過?? equals?? 來在這個桶里找到我們要的類。
那么。重寫了equals(),為什么還要重寫hashCode()呢?
想想,你要在一個桶里找東西,你必須先要找到這個桶啊,你不通過重寫hashcode()來找到桶,光重寫equals()有什么用啊
3。你要對A類排序,有兩種方法,一種就是讓A類實現comparabole結構并實現compareTo()方法,那么可以通過Collections.sort(List??? list)對其進行排序
另一種方法:自己定義一個類B實現Comparator類并實現compare方法,然后通過Collections.sort(List list,B b)進行排序
hashCode()是用來產生哈?,數?#xff0c;而哈?,斒怯脕碓谏⒘写鎯Y構中確定對象的存儲地址的,(這一段在?? Java編程思想?? 中講的很清楚的)象util包中的帶hash的集合類都是用這種存儲結構:HashMap,HashSet,?他們在將對象存儲時(嚴格說是對象引用),需要確定他們的地址吧,而HashCode()就是這個用途的,一般都需要重新定義它的,因為默認情況下,由?Object類定義的?hashCode?方法會針對不同的對象返回不同的整數,這一般是通過將該對象的內部地址轉換成一個整數來實現的,現在舉個例子來說,就拿HashSet來說?? ,在將對象存入其中時,通過被存入對象的hashCode()?來確定對象在HashSet中的存儲地址,通過equals()來確定存入的對象是否重復,hashCode()?,equals()都需要自己重新定義,因為hashCode()默認前面已經說啦,而equals()?? 默認是比較的對象引用,你現在想一下,如果你不定義equals()的話,那么同一個類產生的兩個內容完全相同的對象都可以存入Set,因為他們是通過equals()來確定的,這樣就使得HashSet失去了他的意義,看一下下面這個:
import java.util.*;
public class Test {
??? public static void main(String[] args) {
??????? HashSet set = new HashSet();
??????? for (int i = 0; i <= 3; i++){
??????????? set.add(new Demo1(i,i));???????????
??????? }
??????? System.out.println(set);
??????? set.add(new Demo1(1,1));
??????? System.out.println(set);
??????? System.out.println(set.contains(new Demo1(0,0)));
??????? System.out.println(set.add(new Demo1(1,1)));
??????? System.out.println(set.add(new Demo1(4,4)));
??????? System.out.println(set);
??? }
??? private static class Demo1 {
??????? private int value;
???????
??????? private int id;
??????? public Demo1(int value,int id) {
??????????? this.value = value;
??????????? this.id=id;
??????? }
??????? public String toString() {
??????????? return " value = " + value;
??????? }
??????? public boolean equals(Object o) {
??????????? Demo1 a = (Demo1) o;
??????????? return (a.value == value) ? true : false;
??????? }
??????? public int hashCode() {
??????????? return id;
??????? }
??? }
}
你分別注釋掉hashCode()和?? equals()來比較一下他們作用就可以拉,關鍵要自己動手看看比較的結果你就可以記得很清楚啦
如果還不是很明確可以再看另一個例子:
import java.util.HashMap;
import java.util.Map;
public final class Test {
??? public static void main(String[] args) {
??????? Map m = new HashMap();
??????? m.put(new PhoneNumber(020, 12345678), "shellfeng");
??????? System.out.println(m.get(new PhoneNumber(020, 12345678)));
??? }
??? private static class PhoneNumber {
???????
??????? private short areaCode;
???????
??????? private short extension;
??????? public PhoneNumber(int areaCode, int extension) {
??????????? this.areaCode = (short) areaCode;
??????????? this.extension = (short) extension;
??????? }
??????? public boolean equals(Object o) {
??????????? if (o == this) {
??????????????? return true;
??????????? }
??????????? if (!(o instanceof PhoneNumber)) {
??????????????? return false;
??????????? }
??????????? PhoneNumber pn = (PhoneNumber) o;
??????????? return pn.extension == extension && pn.areaCode == areaCode;
??????? }
???????
??????? public int hashCode() {
??????????? int result = 17;
??????????? result = 37 * result + areaCode;
??????????? result = 37 * result + extension;
??????????? return result;
??????? }
??? }
}
還是那句話:你注釋掉hashCode()比較一下他們作用就可以拉,關鍵要自己動手看看比較的結果你就可以記得很清楚啦
總結
hashCode()方法使用來提高Map里面的搜索效率的,Map會根據不同的hashCode()來放在不同的桶里面,Map在搜索一個對象的時候先通過hashCode()找到相應的桶,然后再根據equals()方法找到相應的對象.要正確的實現Map里面查找元素必須滿足一下兩個條件:
(1)當obj1.equals(obj2)為true時obj1.hashCode()?? ==?? obj2.hashCode()必須為true
(2)當obj1.hashCode() == obj2.hashCode()為false時obj.equals(obj2)必須為false
Java中的集合(Collection)有兩類,一類是List,再有一類是Set。你知道它們的區別嗎?前者集合內的元素是有序的,元素可以重復;后者元素無序,但元素不可重復。
那么這里就有一個比較嚴重的問題了:要想保證元素不重復,可兩個元素是否重復應該依據什么來判斷呢?這就是Object.equals方法了。
但是,如果每增加一個元素就檢查一次,那么當元素很多時,后添加到集合中的元素比較的次數就非常多了。
也就是說,如果集合中現在已經有1000個元素,那么第1001個元素加入集合時,它就要調用1000次equals方法。這顯然會大大降低效率。
哈希算法也稱為散列算法,是將數據依特定算法直接指定到一個地址上。我們可以認為hashCode方法返回的就是對象存儲的物理地址(實際可能并不是,例如:通過獲取對象的物理地址然后除以8再求余,余數幾是計算得到的散列值,我們就認為返回一個不是物理地址的數值,而是一個可以映射到物理地址的值)。
這樣一來,當集合要添加新的元素時,先調用這個元素的hashCode方法,就一下子能定位到它應該放置的物理位置上。如果這個位置上沒有元素,它就可以直接存儲在這個位置上,不用再進行任何比較了;如果這個位置上已經有元素了,就調用它的equals方法與新元素進行比較,相同的話就不存了,不相同就散列其它的地址。所以這里存在一個沖突解決的問題。這樣一來實際調用equals方法的次數就大大降低了,幾乎只需要一兩次。
總結
以上是生活随笔為你收集整理的HashCode和equal方法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 深入浅出JVM
- 下一篇: why在重写equals时还必须重写ha