1. 程式人生 > >== equals hashCode 總結比較

== equals hashCode 總結比較

隨機數序列 board bst 對稱性 equal 參數 date ger 而在

在Java中:

==是運算符,用於比較兩個變量是否相等。

equals,是Objec類的方法,用於比較兩個對象是否相等,默認Object類的equals方法是比較兩個對象的地址,跟==的結果一樣。Object的equals方法如下:

[java] view plain copy
  1. public boolean equals(Object obj) {
  2. return (this == obj);
  3. }

hashCode也是Object類的一個方法。返回一個離散的int型整數。在集合類操作中使用,為了提高查詢速度。(HashMap,HashSet等)

有了這三個基礎概念,區別就簡單了。網上有很多,匯總一下:

java中的數據類型,可分為兩類:
1.基本數據類型,也稱原始數據類型。byte,short,char,int,long,float,double,boolean
他們之間的比較,應用雙等號(==),比較的是他們的值。
2.復合數據類型(類)
當他們用(==)進行比較的時候,比較的是他們在內存中的存放地址,所以,除非是同一個new出來的對象,他們的比較後的結果為true,否則比較後結果為false。 JAVA當中所有的類都是繼承於Object這個基類的,在Object中的基類中定義了一個equals的方法,這個方法的初始行為是比較對象的內存地 址,但在一些類庫當中這個方法被覆蓋掉了,如String,Integer,Date在這些類當中equals有其自身的實現,而不再是比較類在堆內存中的存放地址了。
對於復合數據類型之間進行equals比較,在沒有覆寫equals方法的情況下,他們之間的比較還是基於他們在內存中的存放位置的地址值的,因為Object的equals方法也是用雙等號(==)進行比較的,所以比較後的結果跟雙等號(==)的結果相同。

如果兩個對象根據equals()方法比較是相等的,那麽調用這兩個對象中任意一個對象的hashCode方法都必須產生同樣的整數結果。
如果兩個對象根據equals()方法比較是不相等的,那麽調用這兩個對象中任意一個對象的hashCode方法,則不一定要產生相同的整數結果

從而在集合操作的時候有如下規則:

將對象放入到集合中時,首先判斷要放入對象的hashcode值與集合中的任意一個元素的hashcode值是否相等,如果不相等直接將該對象放入集合中。如果hashcode值相等,然後再通過equals方法判斷要放入對象與集合中的任意一個對象是否相等,如果equals判斷不相等,直接將該元素放入到集合中,否則不放入。

回過來說get的時候,HashMap也先調key.hashCode()算出數組下標,然後看equals如果是true就是找到了,所以就涉及了equals。

《Effective Java》書中有兩條是關於equals和hashCode的:

覆蓋equals時需要遵守的通用約定:
覆蓋equals方法看起來似乎很簡單,但是如果覆蓋不當會導致錯誤,並且後果相當嚴重。《Effective Java》一書中提到“最容易避免這類問題的辦法就是不覆蓋equals方法”,這句話貌似很搞笑,其實想想也不無道理,其實在這種情況下,類的每個實例都只與它自身相等。如果滿足了以下任何一個條件,這就正是所期望的結果:
類的每個實例本質上都是唯一的。對於代表活動實體而不是值的類來說卻是如此,例如Thread。Object提供的equals實現對於這些類來說正是正確的行為。
不關心類是否提供了“邏輯相等”的測試功能。假如Random覆蓋了equals,以檢查兩個Random實例是否產生相同的隨機數序列,但是設計者並不認為客戶需要或者期望這樣的功能。在這樣的情況下,從Object繼承得到的equals實現已經足夠了。
超類已經覆蓋了equals,從超類繼承過來的行為對於子類也是合適的。大多數的Set實現都從AbstractSet繼承equals實現,List實現從AbstractList繼承equals實現,Map實現從AbstractMap繼承equals實現。
類是私有的或者是包級私有的,可以確定它的equals方法永遠不會被調用。在這種情況下,無疑是應該覆蓋equals方法的,以防止它被意外調用:
@Override
public boolean equals(Object o){
throw new AssertionError(); //Method is never called
}

在覆蓋equals方法的時候,你必須要遵守它的通用約定。下面是約定的內容,來自Object的規範[JavaSE6]
自反性。對於任何非null的引用值x,x.equals(x)必須返回true。
對稱性。對於任何非null的引用值x和y,當且僅當y.equals(x)返回true時,x.equals(y)必須返回true
傳遞性。對於任何非null的引用值x、y和z,如果x.equals(y)返回true,並且y.equals(z)也返回true,那麽x.equals(z)也必須返回true。
一致性。對於任何非null的引用值x和y,只要equals的比較操作在對象中所用的信息沒有被修改,多次調用該x.equals(y)就會一直地返回true,或者一致地返回false。
對於任何非null的引用值x,x.equals(null)必須返回false。

結合以上要求,得出了以下實現高質量equals方法的訣竅:
1.使用==符號檢查“參數是否為這個對象的引用”。如果是,則返回true。這只不過是一種性能優化,如果比較操作有可能很昂貴,就值得這麽做。
2.使用instanceof操作符檢查“參數是否為正確的類型”。如果不是,則返回false。一般來說,所謂“正確的類型”是指equals方法所在的那個類。
3.把參數轉換成正確的類型。因為轉換之前進行過instanceof測試,所以確保會成功。
4.對於該類中的每個“關鍵”域,檢查參數中的域是否與該對象中對應的域相匹配。如果這些測試全部成功,則返回true;否則返回false。
5.當編寫完成了equals方法之後,檢查“對稱性”、“傳遞性”、“一致性”。

覆蓋equals時總要覆蓋hashCode
一個很常見的錯誤根源在於沒有覆蓋hashCode方法。在每個覆蓋了equals方法的類中,也必須覆蓋hashCode方法。如果不這樣做的話,就會違反Object.hashCode的通用約定,從而導致該類無法結合所有基於散列的集合一起正常運作,這樣的集合包括HashMap、HashSet和Hashtable。
在應用程序的執行期間,只要對象的equals方法的比較操作所用到的信息沒有被修改,那麽對這同一個對象調用多次,hashCode方法都必須始終如一地返回同一個整數。在同一個應用程序的多次執行過程中,每次執行所返回的整數可以不一致。
如果兩個對象根據equals()方法比較是相等的,那麽調用這兩個對象中任意一個對象的hashCode方法都必須產生同樣的整數結果。
如果兩個對象根據equals()方法比較是不相等的,那麽調用這兩個對象中任意一個對象的hashCode方法,則不一定要產生相同的整數結果。但是程序員應該知道,給不相等的對象產生截然不同的整數結果,有可能提高散列表的性能。

== equals hashCode 總結比較