Java基礎(三):Java字符串比較之==,equals與 hashCode方法的區別與聯繫

概述

==: 比較的是變量(棧)內存中存放的對象的(堆)內存地址,用來判斷兩個對象的地址是否相同,便是否是指相同一個對象。比較的是真正意義上的指針操做。html

equals:用來比較的是兩個對象的內容是否相等,因爲全部的類都是繼承自java.lang.Object類的,因此適用於全部對象,String中的類是重寫了object類裏的equal()方法,而在本來的object類中,返回的是==的判斷,若是沒有對該方法進行覆蓋的話,調用的仍然是Object類中的方法。java

hashCode : Object 的 native方法 , 獲取對象的哈希值,用於肯定該對象在哈希表中的索引位置,它其實是一個int型整數。算法

關係運算符==

基本數據類型

在Java中有八種基本數據類型:數組

  • 浮點型:float(4 字節), double(8 字節)this

  • 整型:byte(1 字節), short(2 字節), int(4 字節) , long(8 字節)spa

  • 字符型: char(2 字節).net

  • 布爾型: boolean設計

對於這八種基本數據類型的變量,變量直接存儲的是「值」,基本數據類型之間的比較須要用雙等號(==),由於他們比較的是值指針

引用數據類型

接口、類、數組等非基本數據類型code

Java中的字符串String屬於引用數據類型。由於String是一個類

引用類型的變量存儲的並非「值」自己,而是與其關聯的對象在內存中的地址,當他們用(==)進行比較的時候,比較的是他們在內存中的存放地址,因此,除非是同一個new出來的對象,他們的比較後的結果爲true,不然比較後結果爲false。由於每new一次就會從新開闢一個新的堆內存空間

String s1 = "小新";
String s2 = "小新";
System.out.println(s1 == s2);   //true
String str1 = new String("小新");
String str2 = new String("小新");
System.out.println(s1 == str1); //false
System.out.println(str1 == str2); //false
複製代碼

s1 == s2爲true,是由於s1和s2都是字符串字面值"小新"的引用,指向同一塊地址,因此相等。

s1== str1爲false,是由於經過new產生的對象在堆中,str1是堆中變量的引用,而s1是指向字符串字面值"小新"的引用,地址不一樣因此不相等。

str1 == str2爲flase,是由於即便內容相同,因爲不是指向同一個對象,也會返回false。

小結

  • 若操做數的類型是基本數據類型,則該關係操做符判斷的是左右兩邊操做數的是否相等
  • 若操做數的類型是引用數據類型,則該關係操做符判斷的是左右兩邊操做數的內存地址是否相同。也就是說,若此時返回true,則該操做符做用的必定是同一個對象。

equals

來源

equals,是Objec類的方法,源代碼以下:

public boolean equals(Object obj) {
    return (this == obj);
}
複製代碼

可見Objec的equals方法,直接調用==,比較對象地址,便是否指向同一個對象。

不一樣的子類,能夠重寫此方法,進行兩個對象的equals的判斷。

String類源碼中重寫的equals方法以下:

public boolean equals(Object anObject) {   
    if (this == anObject) {     // 先判斷是否爲同一對象
        return true;
    }
    if (anObject instanceof String) {   // 再判斷類型是否一致,
        // 最後判斷內容是否一致.
        String anotherString = (String)anObject;
        int n = count;
        if (n == anotherString.count) {
        char v1[] = value;
        char v2[] = anotherString.value;
        int i = offset;
        int j = anotherString.offset;
        while (n-- != 0) {
            if (v1[i++] != v2[j++])
            return false;
        }
        return true;
        }
    }
    return false;
}
複製代碼

使用equals方法,內部實現分爲三個步驟:

  • 先比較引用是否相同(是否爲同一對象),
  • 再判斷類型是否一致(是否爲同一類型),
  • 最後比較內容是否一致

equals 重寫原則

  • 自反型,對於任何非null的引用值x,也就是本身等於本身x.equals(x)是true
  • 對稱性,對於任何非null的引用值x和y,也就是x.equals(y)等於y.equals(x)
  • 傳遞性,對於任何非null的引用值x,y和z,若是x.equals(y)返回是「true」,並且y.equals(z)返回是「true」,那麼x.equals(z)也應該返回是「true」
  • 一致性,對於任何非null的引用值x和y,屢次調用x.equals(y)獲得的結果是同樣的,只要引用沒有被修改
  • 非空性,全部的對象都不能爲空,對於任意非空引用x,x.equals(null)應該返回false。

小結

所以,對於 equals 方法:

  • Object類中equals方法本意是比較兩個對象是否相同
  • 必要的時候,咱們須要重寫該方法,避免違背本意,且要遵循上述原則

hashCode

來源

hashCode 方法是基類Object中的 實例native方法,所以對全部繼承於Object的類都會有該方法。

他的源碼以下:

public native int hashCode();
複製代碼

說明是一個本地方法,它的實現是根據本地機器相關的。固然咱們能夠在本身寫的類中覆蓋hashcode()方法,好比String、Integer、Double等這些類都是覆蓋了hashcode()方法的。例如在String類中定義的hashcode()方法以下:

public int hashCode() {
    int h = hash;
    if (h == 0) {
        int off = offset;
        char val[] = value;
        int len = count;

        for (int i = 0; i < len; i++) {
            h = 31 * h + val[off++];
        }
        hash = h;
    }
    return h;
}
複製代碼

想要弄明白hashCode的做用,必需要先知道Java中的集合。   ​ 總的來講,Java中的集合(Collection)有兩類,一類是List,再有一類是Set。前者集合內的元素是有序的,元素能夠重複;後者元素無序,但元素不可重複。這裏就引出一個問題:要想保證元素不重複,可兩個元素是否重複應該依據什麼來判斷呢? ​ 這就是Object.equals方法了。可是,若是每增長一個元素就檢查一次,那麼當元素不少時,後添加到集合中的元素比較的次數就很是多了。也就是說,若是集合中如今已經有1000個元素,那麼第1001個元素加入集合時,它就要調用1000次equals方法。這顯然會大大下降效率。
​ 因而,Java採用了哈希表的原理。哈希(Hash)其實是我的名,因爲他提出一哈希算法的概念,因此就以他的名字命名了。哈希算法也稱爲散列算法,是將數據依特定算法直接指定到一個地址上,初學者能夠簡單理解,hashCode方法實際上返回的就是對象存儲的物理地址(實際可能並非)。
​ 這樣一來,當集合要添加新的元素時,先調用這個元素的hashCode方法,就一會兒能定位到它應該放置的物理位置上。若是這個位置上沒有元素,它就能夠直接存儲在這個位置上,不用再進行任何比較了;若是這個位置上已經有元素了,就調用它的equals方法與新元素進行比較,相同的話就不存了,不相同就散列其它的地址。因此這裏存在一個衝突解決的問題。這樣一來實際調用equals方法的次數就大大下降了,幾乎只須要一兩次。

hashCode()和equals()關係

  • equals()相等的兩個對象,hashcode()必定相等;
  • hashcode()相等,那麼equals()有可能相等,也有可能不等 ;
  • 若是hashcode()不等,equals()必定不相等;
  • 通常來說,equals 這個方法是給用戶調用的,而 hashcode 方法通常用戶不會去調用 ;
  • 當一個對象類型做爲集合對象的元素時,那麼這個對象應該擁有本身的equals()和hashCode()設計,並且要遵照前面所說的幾個原則。

爲何重寫equals的同時也要重寫hashCode?

1.使用hashcode方法提早校驗,能夠避免每一次比對都調用equals方法,提升效率

2.保證是同一個對象,若是重寫了equals方法,而沒有重寫hashcode方法,會出現equals相等的對象,hashcode不相等的狀況,重寫hashcode方法就是爲了不這種狀況的出現。

小結

  1. hashcode是系統用來快速檢索對象而使用
  2. equals方法本意是用來判斷引用的對象是否一致
  3. 重寫equals方法和hashcode方法時,equals方法中用到的成員變量也一定會在hashcode方法中用到,只不過前者做爲比較項,後者做爲生成摘要的信息項,本質上所用到的數據是同樣的,從而保證兩者的一致性

參考資料

blog.csdn.net/justloveyou…

www.cnblogs.com/aspirant/p/…

www.iteye.com/blog/bijian…

相關文章
相關標籤/搜索