1. 程式人生 > >Effective Java 總結(二) 對於所有物件都通用的方法

Effective Java 總結(二) 對於所有物件都通用的方法

在改寫equals的時候請遵守通用約定

不改寫equals方法時,每個例項只與自身相等,如果滿足一下任意一個條件,則不需要改寫equals方法:

  • 一個類的例項本質上都是唯一的
  • 不關心類是否支援“邏輯相等”功能
  • 超類已經改寫了equals方法
  • 類是私有的,並且可以確定它的equals方法永遠不會被呼叫

改寫equals方法時,需要遵守的約定:

  • 自反性(自己和自己相等)
  • 對稱性(x和y相等,反過來y也和x相等)
  • 傳遞性(x與y相等,y與z相等,則x與z相等)
  • 一致性(x與y相等,則不論進行多少次比較,結果都不會變)
  • 非空性(o.equals(null)一定返回false)

改寫equals時總是要改寫hashCode

改寫一個類的equals方法後,兩個不同的物件可能在邏輯上是相等的,但是根據Object的hashCode方法來看,它們僅僅是兩個物件,沒有其他共同的地方,因此hashCode方法返回的不會是兩個相等的整數,這可能會導致一些問題。

如果你把一個物件放入Map中當作Key,此後你建立一個與原物件邏輯相等的新物件用作Key去取值,你會發現結果返回的是null

因此你應該針對物件間用來進行邏輯比較的值來確定hashCode,該值應該是獲取hashCode表示式中的唯一變數。

總是要改寫toString

這個不用多說了,物件如果不改寫toString方法,會直接輸出“類名@:hashCode”,為了方便除錯,總是要改寫物件的toString方法,eclipse/Myeclipse都提供這個方法。

一個改寫toString方法的例子

public class Person {
	public String name;
	public boolean sex;
	public int age;
	
	@Override
	public String toString() {
		return "Person [name=" + name + ", sex=" + sex + ", age=" + age + "]";
	}

}

謹慎地改寫clone

按照書中的話來講,能不重寫clone就不要去重寫,因為它帶來的問題太多了。關於“深拷貝”和“淺拷貝”,可以轉戰這篇部落格:【Java深入】深拷貝與淺拷貝詳解

,但這篇只提到了反序列化方法,其實還可以用反射和表達樹來實現深拷貝。

書中是不建議自定義重寫clone方法的,如果非要重寫書中總結為一句話:clone方法就是一個構造器,你必須確保它不會傷害到原始的物件,並確保正確地建立被克隆物件中的約束條件。

檢視Cloneable介面實際上可以發現裡面什麼方法都沒有,clone方法卻來自Object類,繼承了Cloneable介面為什麼就能重寫clone方法了呢?原因在於clone方法在Object類中的修飾符是protected,而Cloneable介面和Object處於同一個包下,熟悉修飾符的都知道protected的許可權限定在同一個包下或者其子類。Cloneable和Object同屬於一個包,Cloneable自然能繼承clone方法,繼承了Cloneable介面的成為了它的子類同樣也就繼承了clone方法。

考慮實現Comparable介面

其實我感覺這點沒什麼可說的,就是實現Comparable介面中的compareTo方法,自己編寫比較規則。

此外Arrays和Collections都已經提供了sort方法,而且如果需要在陣列/集合內部定義排序規則,還可以新建一個Comparator例項,自己實現compare方法,再為陣列或集合呼叫就好了。