通常在面試中會被問到equals方法和==的差別,以及有沒有重寫過equals方法,以及重寫equals方法的約定是什麼?
下面簡單的介紹一下我的了解:
首先,在比較基本類型中==和equals方法沒有任何差別。
但是在比較引用類型,如對象中
equals 是通常是比較的是對象的執行個體是否相同。
==通常是比較的是對象的執行個體的位址是否相同即對象執行個體的id。這是兩個最重要的差別。
其次,重寫equals方法的原則或者說約定是什麼,以及什麼時候應該覆寫equals呢
如果類具有自己特有的“邏輯相等”概念(不等同于對象等同的概念),而且超類還沒有覆寫equals以實作期望的行為,這個時候我們要覆寫equals方法(通常屬于值類的情況)。—來自于effective Java 中文版
但是在覆寫equals方法的時候要遵守的約定如下:
equals方法實作了等價的關系
1.自反性。對于任何非null的引用值x,x.equals(x)都必須傳回true
2.對稱性。對于任何非null的引用值x和y,當且僅當x.equals(y)傳回true的時候,y.equals(x)也必須傳回true
3.傳遞性。對于任何非null的引用值x,y和z,如果x.equals(y)傳回true,y.equals(z)傳回true,則x.equals(z)也必須傳回true。
4.一緻性。對應任何非null的引用值x,y,隻要equals比較操作在對象中所用的資訊沒有被修改,多次調用x.equals(y)就會一緻性的傳回true或者一緻性的傳回false。—–來自于effective Java 中文版
由一個例子引出的四個方面談一談經典的==和equals的問題
代碼:
private staticvoid test(){
String a =“a”+”b”+1;
String b =“ab1”;
System.out.println(a==b);
}
關于這一段程式會輸出的結果是什麼?你可能會說是true或者false,那真正的答案是true;我們從下面4
個方面來分析這個問題
1. 關于“==”是幹什麼的?
1.1 關于“==”
首先要知道“==”用于比對記憶體單元上的内容,其實就是一個數字,計算機内部也隻有數字。在java中,
當“==”比對的時候,其實就是對比兩個記憶體單元的内容是否一樣。
如果是原始類型byte、boolean、short、char、int、float、double等就是直接比較他們的值。
如果是引用(reference),比較的是引用的值,可以被認為是對象的邏輯位址。如果兩個引用使用“==
”比較操作,就是比較行營的兩個對象的位址是否一樣。如果一樣則傳回true,否則傳回false。
2. 關于equals是幹什麼的?
2.1關于“equals”
說起equals方法,大家都不陌生,是在Object類中被定義的,他的定義就是預設使用“==”來比對的。也
就是說如果我們不重寫equals方法,并且對應的父類中也都沒有重寫過equals,可以預設為是用equals使
用的是比較對象的位址是否相同。
而equals之是以存在,是希望使用者的子類去重寫這個方法,實作對比值的功能。類似的String就實作了
equals方法。自己去實作這個方法是因為當我們兩個對象對比時隻選取其中關鍵的業務屬性上面來。确定
他們是否是“一緻的或者是相似的”,則傳回true/false即可。
注:相似的了解
有時我們在一個情景業務條件下,并不一定需要絕對相同才可以認定為相同,比如我們都知道我們的親子
鑒定的結果,出來都沒有100%的可能性,那現在就要發揮這個相似的作用了,我們可以規定隻要他的報告
相似度為98%以上,我就認為是親生的即(傳回true否則傳回false)。也就是說,兩個對象的值是否相等
是自己的業務來決定的而不是java語言本身所決定的。
3. a和b在記憶體中是如何配置設定的(是怎樣的)?
回到頁首的例子中,其中等号說明a和b是指向同一塊記憶體空間的,就想兩個人拿到同一個公司的offer一
樣,所有答案才是true;
4. jvm在編譯階段的優化方案
a引用是通過“+”指派的,b引用是直接指派的,那為什麼a和b會共享一個記憶體單元?這就是jvm的“編譯
時優化”。
當我們的編譯器在編譯代碼String a = “a”+”b”+1,時會将其編譯為String a =”ab1”;因為他們都
是常量,編譯器認為這3個常量的疊加會達到固定的值,無需運作時候進行技算,所有就會這樣優化。
這樣做的目的是我們把同樣的業務邏輯放在一起執行,更能解決資源的均衡和輝煌。