Java基礎:Java 中的 ==, equals 與 hashCode 的區別與聯繫

概述

概念:

  • == : 該操作符生成的是一個boolean結果,它計算的是操作數的值之間的關係
  • equals : Object 的 實例方法,比較兩個對象的content是否相同
  • hashCode : Object 的 native方法 , 獲取對象的哈希值,用於確定該對象在哈希表中的索引位置,它實際上是一個int型整數

二、關係操作符 ==

1、操作數的值

基本數據類型變量

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

  • 浮點型:float(4 byte), double(8 byte)
  • 整型:byte(1 byte), short(2 byte), int(4 byte) , long(8 byte)
  • 字符型: char(2 byte)
  • 布爾型: boolean(JVM規範沒有明確規定其所佔的空間大小,僅規定其只能夠取字面值”true”和”false”)

對於這八種基本數據類型的變量,變量直接存儲的是“值”。因此,在使用關係操作符 == 來進行比較時,比較的就是“值”本身。要注意的是,浮點型和整型都是有符號類型的(最高位僅用於表示正負,不參與計算【以 byte 為例,其範圍為 -2^7 ~ 2^7 - 1,-0即-128】),而char是無符號類型的(所有位均參與計算,所以char類型取值範圍為0~2^16-1)。

引用類型變量

在Java中,引用類型的變量存儲的並不是“值”本身,而是與其關聯的對象在內存中的地址。比如下面這行代碼:

String str1;

這句話聲明瞭一個引用類型的變量,此時它並沒有和任何對象關聯。 而通過 new 來產生一個對象,並將這個對象和str1進行綁定:

str1= new String("hello");

那麼 str1 就指向了這個對象,此時引用變量str1中存儲的是它指向的對象在內存中的存儲地址,並不是“值”本身,也就是說並不是直接存儲的字符串”hello”。這裡面的引用和 C/C++ 中的指針很類似。

小結

因此,對於關係操作符 ==:

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

equals

在初學Java的時候,很多人會說在比較對象的時候,==是比較地址,equals()是比較對象的內容,誰說的?

看看equals()方法在Object類中的定義:

public boolean equals(Object obj){

return (this == obj);

}

這是比較內容麼?明顯是比較指針(地址)麼…

但是為什麼會有equals是比較內容的這種說法呢?

因為在String、Double等封裝類中,已經重載(overriding)了Object類的equals()方法,於是有了另一種計算公式,是進行內容的比較。

比如在String類中:

 
public int hashCode() {
int h = hash;
if (h == 0) {
char val[] = value;
int len = count;
for (int i = 0; i < len; i++) {
h = 31*h + val[off++];
}
hash = h;
}
return h;
}

hashCode

在Object類中的定義為:

public native int hashCode();

是一個本地方法,返回的對象的地址值。

但是,同樣的思路,在String等封裝類中對此方法進行了重寫。方法調用得到一個計算公式得到的 int值.

hashCode和equlas的關係

  • 1、如果兩個對象相同(即用equals比較返回true),那麼它們的hashCode值一定要相同;
  • 2、如果兩個對象的hashCode相同,它們並不一定相同(即用equals比較返回false)
  • 原因:從散列的角度考慮,不同的對象計算哈希碼的時候,可能引起衝突,大家一定還記得數據結構中。

自我的理解:由於為了提高程序的效率才實現了hashcode方法,先進行hashcode的比較,如果不同,那沒就不必在進行equals的比較了,這樣就大大減少了equals比較的 次數,這對比需要比較的數量很大的效率提高是很明顯的,一個很好的例子就是在集合中的使用;

我們都知道java中的List集合是有序的,因此是可以重複的,而set集合是無序的,因此是不能重複的,那麼怎麼能保證不能被放入重複的元素呢,但靠equals方法一樣比較的 話,如果原來集合中以後又10000個元素了,那麼放入10001個元素,難道要將前面的所有元素都進行比較,看看是否有重複,歐碼噶的,這個效率可想而知,因此hashcode 就應遇而生了,java就採用了hash表,利用哈希算法(也叫散列算法),就是將對象數據根據該對象的特徵使用特定的算法將其定義到一個地址上,那麼在後面定義進來的數據 只要看對應的hashcode地址上是否有值,那麼就用equals比較,如果沒有則直接插入,只要就大大減少了equals的使用次數,執行效率就大大提高了。 繼續上面的話題,為什麼必須要重寫hashcode方法,其實簡單的說就是為了保證同一個對象,保證在equals相同的情況下hashcode值必定相同,如果重寫了equals而未重寫 hashcode方法,可能就會出現兩個沒有關係的對象equals相同的(因為equal都是根據對象的特徵進行重寫的),但hashcode確實不相同的。


分享到:


相關文章: