1. 程式人生 > >《Effective Java》:對於所有物件都通用的方法

《Effective Java》:對於所有物件都通用的方法

本系列皆為讀書筆記,“好記性不如爛筆頭”,勤看,也要勤記錄。此篇讀書筆記來自《Effective Java》。

儘管Object是一個具體類,但設計它主要是為了擴充套件。它所有的非final方法都有明確的通用規定。任何一個類,在覆蓋這些方法的時候,都有責任去遵守這些通用規定,如果不能做到這一點,其他依賴於這些規定的類就無法結合該類一起正常運作。 

第八條:覆蓋equals時請遵守通用規定 
如果類具有自己特有的邏輯相等概念(不同於物件等同的概念),而且超類還沒有覆蓋equals以實現期望的行為,這時就需要覆蓋equals方法。在覆蓋時,需要遵守下面的通用約定; 
1.自反性   x.equals(x)必須返回true 

2.對稱性   y.equals(x)返回true時,x.equals(y)必須返回true 
3.傳遞性   如果x.equals(y)返回true,y.equals(z)返回true, 那麼x.equals(z)返回true 
4.一致性   只要equals的比較操作在物件中所用的資訊沒有被修改,多次呼叫x.equals(y)就會一致返回true,或者一致返回false 
5.對於非null的引用值x,x.equals(null)必須返回false。 

下面是實現高質量equals方法的訣竅: 
1.使用==操作符檢查“引數是否為這個物件的引用”。 
2.使用instanceof操作符檢查“引數是否為正確的型別”。 

3.把引數轉換成正確的型別。 
4.對於該類中的每個“關鍵”域,檢查引數中的域是否與該物件中對應的域相匹配。 
5.當你編寫完成了equals方法,應該檢查是否是對稱的、傳遞的、一致的。 
6.不要企圖讓equals方法過於智慧 
7.不要將equals宣告中的Object物件替換成其他的型別 
8.覆蓋equals方法時總要覆蓋hashCode 

第九條:覆蓋equals時總要覆蓋hashCode
如果不覆蓋hashCode,將導致該類無法結合所有基於雜湊的集合一起正常工作,比如:HashMap,HashSet,Hashtable 
下面是約定的內容; 
1.在應用程式執行期間,只要物件的equals方法的比較操作符所用的資訊沒有被修改,那麼對同一個物件呼叫多次,hashCode方法都必須返回一個整數。在一個程式的多次執行過程中,可以不一致。 

2.如果兩個物件根據equals方法比較是相等的,那麼呼叫這兩個物件的任何一個hashCode方法都必須產生同樣的整數結果 
3.如果兩個物件不相等,他們的hashCode方法不一定產生不同的整數結果。但是,給不相等的物件產生不同的整數結果,有可能提高散列表的效能。 

第十條:始終要覆蓋toString
雖然Object提供了toString的一個實現,但返回的字串通常不是使用者期望看到的。它包含類的名稱,以及一個“@“,接著就是雜湊嗎的無符號十六進位制表示法。當物件被傳遞給println或者被偵錯程式打印出來時,toString方法會被自動呼叫。提供好的toString方法,不僅有利於這個類的例項,同樣也有益於包含這些例項的引用的物件。 
在實現toString時,你可以決定是否在文件中指定返回值的格式。這樣增強可讀性,但一旦指定,就必須始終如一的堅持。所以無論是否指定格式,都應該在文件中明確的表明你的意圖。 

第十一條:謹慎的覆蓋clone
Cloneable介面的目的是作為物件的一個mixin介面,表明這樣的物件允許克隆。但它缺少一個clone方法,Object的clone方法是受保護的。如果不借用反射,就不能達到呼叫clone方法的目的。既然Cloneable並沒有包含任何方法,那麼它到底有什麼作用呢? 
如果一個類實現了Cloneable,那麼Object的clone方法就返回該物件的逐域拷貝,否則就丟擲異常。因此,該類必須遵守一個複雜的,不可實施的協議。由此得到一種語言之外的機制:無需呼叫構造器就可建立物件。 
實際上,clone方法就是另一個構造器,但必須確保他不會傷害原始的物件,並確保正確的建立被克隆物件中的約束條件。 
總之,所有實現了Cloneable介面的類都應該用一個公有的方法覆蓋clone。該方法先呼叫super.clone,然後修正任何需要修正的域。一般情況下,這意味著要拷貝任何包含內部”深層結構“的可變物件,並用指向新物件的引用代替原來指向這些物件的引用。 

第十二條:考慮實現Comparable介面
compareTo方法並沒有在Object中宣告,相反,它是Comparable介面中唯一的方法。compareTo方法不但允許進行簡單的等同性比較,而且允許執行順序比較。類實現了Comparable介面就表明它的例項具有內在的排序關係。實現排序就這麼簡單: 
Arrays.sort(a); 
如果你正在編寫一個值類,它具有非常明顯的內在排序關係,比如按字母排序、按數值排序或者按年代排序,那你就應該堅決考慮實現這個介面。當該物件小於、等於、大於指定物件的時候,分別返回一個負整數、0、正整數。如果沒法進行比較,丟擲異常。