同一性(identity):
java提供了判等運算子:==和!=,可以作用於基本數實值型別,boolean型數值,參考型別.例如:
兩個引用ref1和ref2引用了相同的對象或者都是null,那麼運算式ref1==ref2的值為true,就算這兩個引用具有不同的型別宣告也是如此,否則運算式的值為false.
判等運算子測試的是引用的同一性,而不是對象的等同性.若兩個引用指向同一個對象,那麼它們是同一的.若兩個對象邏輯上擁有同樣的值,那麼它們是等同的.等同性是通過Object定義的equals方法來進行檢驗的.對於那些等同性和同一性不是一回事的類,應覆蓋equals方法,因為:
Object.equals假定一個對象只和它本身等同.
注意:
由於數組沒有定義自已的方法,僅僅繼承了Object的方法,所以其equals方法總是基於同一性而不是等同性,java.util.Arrays類中的equals方法是通過計算基於數組內容的散列碼來比較數組的等同性.
等同性(equivalence):
Object中的equals比較:
比較接受者和參數對象的記憶體位置,若子類沒有提供equals實現,那麼使用預設的比較記憶體位置的equals實現.Java API文檔關於Object的equals方法的部分,提供了一個列表,詳細的定義了兩個對象之間的相等關係:
1.自反性(reflexivity):x.equals(x)
2.對稱性(symmetry):x.equals(y) 若且唯若y.equals(x)
3.傳遞性(transitivity):如果x.equals(y) 並且y.equals(z),那麼:x.equals(z)
4.一致性(consistency):給定一致的狀態,x.equals(y)返回一致的結果
5.可以與null比較(comparison to null):x.equals(null)
相關應用:
1.參數為null的情況下返回false的防衛子句
@override
public boolean equals(Object object){
if(object == null) return false;
...
}
2.apple and orange
如果有人向方法扔進一個"orange",立即返回false防衛(bg)子句,該防衛子句確保參數的類型與接受者的類型相匹配
@override
public boolean equals(Object object){
if(object == null) return false;
if(this.getClass() !=object.getClass()) return false;
...
}
3.為什麼不用equals?
類常量是唯一的:所有類對象共用一個執行個體,正因為類常量的唯一性,所以可以使用判等運算子 != 來比較類常量,而不必一定使用方法equals.
當然也有人更傾向於 instanceof,如果某個對象是目標類的執行個體,或者目標類的子類執行個體,那麼操作符 instanceof返回true.如下:
public boolean equals(Object object){
if(object == null) return false;
if(!(object instanceof User)) return false;
...
}
推薦使用方法getClass而不是instanceof,來比較兩個類的類型,只有兩個對象屬於同一個類,getClass才返回:true,若需要在繼承層次上不考慮層次位置的比較對象,那就使用instanceof
4.字串字面常量,等同性和記憶體限定
一般來說使用判等運算子:==,來比較字串會得到錯誤的結果.然而對於兩個相同內容的字串字面常量來說,他們將指向同一個String對象,例如:
String str="abc";
if(str=="abc"){
....
}
注意:
只有當所涉及的所有字串引用指向的都是字串字面常量時,才可以這麼作,如果str改成引用一個產生的String對象,那麼==判等運算子就返回false.為瞭解決這個問題,可以對不能確切知道是否引用到了字串字面常量進行記憶體限定(intern).
intern方法:
該方法將返回一個String對象,它與被調用該方法的String對象是具有同樣的內容,然而任何兩個內容相同的字串在被調用intern方法後,返回的String對象都是相同的,這種機制使得我們可以通過比較字串引用來測試其等同性,從而取代執行速度極慢的對字串內容的測試.
int putIn(String key){
String u
<