HashCode和equal方法

equals()反映的是對象或變量具體的值,即兩個對象裏面包含的值--多是對象的引用,也多是值類型的值。html

而hashCode()是對象或變量經過哈希算法計算出的哈希值。java

之因此有hashCode方法,是由於在批量的對象比較中,hashCode要比equals來得快,不少集合都用到了hashCode,好比HashTable。算法

 

兩個obj,若是equals()相等,hashCode()必定相等。shell

兩個obj,若是hashCode()相等,equals()不必定相等(Hash散列值有衝突的狀況,雖然機率很低)。編程

因此:數據結構

能夠考慮在集合中,判斷兩個對象是否相等的規則是:this

第一步,若是hashCode()相等,則查看第二步,不然不相等;spa

第二步,查看equals()是否相等,若是相等,則兩obj相等,不然仍是不相等。code

 

一、首先equals()和hashcode()這兩個方法都是從object類中繼承過來的。

equals()是對兩個對象的地址值進行的比較(即比較引用是否相同)。

hashCode()是一個本地方法,它的實現是根據本地機器相關的。

二、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」。

三、equals()相等的兩個對象,hashcode()必定相等;

反過來:hashcode()不等,必定能推出equals()也不等;

hashcode()相等,equals()可能相等,也可能不等。 htm

 

引用:http://blog.sina.com.cn/s/blog_59e0c16f0100xne7.html

一、爲何要重載equal方法?

答案:由於Object的equal方法默認是兩個對象的引用的比較,意思就是指向同一內存,地址則相等,不然不相等;若是你如今須要利用對象裏面的值來判斷是否相等,則重載equal方法。

二、 爲何重載hashCode方法?

答案:通常的地方不須要重載hashCode,只有當類須要放在HashTable、HashMap、HashSet等等hash結構的集合時纔會重載hashCode,那麼爲何要重載hashCode呢?就HashMap來講,比如HashMap就是一個大內存塊,裏面有不少小內存塊,小內存塊裏面是一系列的對象,能夠利用hashCode來查找小內存塊hashCode%size(小內存塊數量),因此當equal相等時,hashCode必須相等,並且若是是object對象,必須重載hashCode和equal方法。

三、 爲何equals()相等,hashCode就必定要相等,而hashCode相等,卻不要求equals相等?

答案:一、由於是按照hashCode來訪問小內存塊,因此hashCode必須相等。

二、HashMap獲取一個對象是比較key的hashCode相等和equal爲true。

之因此hashCode相等,卻能夠equal不等,就好比ObjectA和ObjectB他們都有屬性name,那麼hashCode都以name計算,因此hashCode同樣,可是兩個對象屬於不一樣類型,因此equal爲false。

四、 爲何須要hashCode?

一、 經過hashCode能夠很快的查到小內存塊。
二、經過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()是用來產生哈希瑪的,而哈希瑪是用來在散列存儲結構中肯定對象的存儲地址的,(這一段在   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方法的次數就大大下降了,幾乎只須要一兩次。

相關文章
相關標籤/搜索