1. 程式人生 > >java面試(1): java中==和equals和hashCode的區別

java面試(1): java中==和equals和hashCode的區別

1."=="

    "=="運算子是比較兩個變數的值是否相等。也就是說,該運算子用於比較變數對應的記憶體中所儲存的值是否相等,要比較兩個基礎型別的資料或兩個引用變數是否相等,只能使用"=="運算子。

    具體而言,如果兩個變數是基礎型別,可以直接使用"=="運算子判斷對應的值是否相等。如果一個變數指向的是物件(引用型別),那麼,此時涉及兩塊記憶體,指向的物件本身佔用一塊記憶體(堆記憶體),變數本身也佔用一塊記憶體,例如對於語句String s = new String(),變數s佔用一塊儲存空間,而new String()佔用另一塊儲存空間,此時變數s所對應記憶體中的儲存數值就是指向的物件佔用的那塊記憶體的首地址。對於引用型別的變數,如果判斷兩個變數是否指向一個相同的物件,即要比較這兩個變數對應的記憶體中的數值是否相同(這兩個變數是否指向同一個物件),這時可以通過"=="運算子來進行比較,但是如果要比較這兩個物件的內容是否相等,使用"=="就無法實現了。

總結:

    "=="運算子的作用的是比較兩個變數的值是否相等,這裡要注意當比較的變數是引用變數時,比較的是它們指向的物件的地址是否相同,而不能比較它們指向物件的內容是否相同。

 

2. equals()方法

    equals()是Object類中的方法,每個Java類都繼承自Object類,所以每個java類都具有equals()方法,Object中的equals方法直接使用"=="運算子來返回比較的兩個物件結果,所以在子類沒有覆蓋equals方法的情況下,equals()與"=="結果是一樣的,都是比較物件的引用是否為同一個(也就是兩個引用變數指向的物件的地址是否相同)。

    相比"=="運算子,equals方法的特殊之處就是可以被覆蓋,所以可以通過覆蓋,讓該方法比較的不是引用物件的地址,而可以是我們想要比較的任何邏輯(自己可以隨便實現,例如: String類中的equals方法是用於比較兩個引用變數指向的物件的內容是否相同),以下面的程式碼為例:

String test1= new String("hello");

String test2= new String("hello");

    兩個new語句建立了兩個物件,然後分別用test1test2指向一個物件,這是兩個不同的物件,他們的首地址是不相同的,即

test1test2儲存的數值是不相同的,所以表示式test1==test2將返回false,而這兩個物件的內容是相同的,所以test1.equals(test2)方法將返回true。通過以上例子可以說明,如果一個類沒有複寫euqals方法,那麼它就從Object中繼承equals方法,並且預設使用"=="運算子來進行比較,也就是在比較兩個物件的引用是否相同,因此equals和==會得到相同的結果。若比較兩個獨立的物件,則總會返回false。如果編寫的類希望能夠比較該類建立的兩個例項物件的內容是否相等,那麼必須覆蓋equals方法。

3.hashCode()方法

    hashCode是根類Obeject中的方法。預設情況下,Object中的hashCode() 返回物件的32位jvm記憶體地址。也就是說如果物件不重寫該方法,則返回相應物件的32位JVM記憶體地址。且是int型別的雜湊碼。物件的雜湊碼是為了更好的支援基於雜湊機制的Java集合類,例如 Hashtable, HashMap, HashSet 等。

官方文件:

返回該物件的雜湊碼值。支援此方法是為了提高雜湊表(例如 java.util.Hashtable 提供的雜湊表)的效能。

hashCode 的常規協定是:

* 在 Java 應用程式執行期間,在對同一物件多次呼叫 hashCode 方法時,必須一致地返回相同的整數,前提是將物件進行 equals 比較時所用的資訊沒有被修改。從某一應用程式的一次執行到同一應用程式的另一次執行,該整數無需保持一致。

* 如果根據 equals(Object) 方法,兩個物件是相等的,那麼對這兩個物件中的每個物件呼叫 hashCode 方法都必須生成相同的整數結果。

* 如果根據 equals(java.lang.Object) 方法,兩個物件不相等,那麼對這兩個物件中的任一物件上呼叫 hashCode 方法不 要求一定生成不同的整數結果。但是,程式設計師應該意識到,為不相等的物件生成不同整數結果可以提高雜湊表的效能。

實際上,由 Object 類定義的 hashCode 方法確實會針對不同的物件返回不同的整數。(這一般是通過將該物件的內部地址轉換成一個整數來實現的,但是 JavaTM 程式語言不需要這種實現技巧。)

返回:此物件的一個雜湊碼值。

從官方文件可以提取3點:

1、重寫了euqls方法的物件必須同時重寫hashCode()方法。

2、如果2個物件通過equals呼叫後返回是true,那麼這兩個物件的hashCode方法也必須返回同樣的int型雜湊碼。

3、如果2個物件通過equals返回false,他們的hashCode返回的值允許相同。(然而,程式設計師必須意識到,hashCode返回獨一無二的雜湊碼,會讓儲存這個物件的hashtables更好地工作。)

 

網上關於這個說的比較好的一段話

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()有什麼用啊

總結: hashcode()主要就是用來快速查詢用的,而equals()主要用來比較兩個物件是否相等。

下面再次將equals和hashCode放在一起簡單的做個總結:

(1)繫結。當equals方法被重寫時,通常有必要重寫 hashCode 方法,以維護 hashCode 方法的常規協定,該協定宣告相等物件必須具有相等的雜湊碼。

(2)繫結原因。Hashtable實現一個雜湊表,為了成功地在雜湊表中儲存和檢索物件,用作鍵的物件必須實現 hashCode 方法和 equals 方法。同(1),必須保證equals相等的物件,hashCode 也相等。因為雜湊表通過hashCode檢索物件。

(3)預設。

==預設比較物件在JVM中的地址。

hashCode 預設返回物件在JVM中的儲存地址。

equal比較物件,預設也是比較物件在JVM中的地址,同==

 

參考連結:

https://my.oschina.net/ccqy66/blog/507922

https://blog.csdn.net/fenglibing/article/details/8905007