1 package cn.galc.test; 2 3 public class TestEquals { 4 public static void main(String[] args) { 5 /** 6 * 這裏使用構造方法Cat()在堆內存裏面new出了兩隻貓, 7 * 這兩隻貓的color,weight,height都是同樣的, 8 * 但c1和c2卻永遠不會相等,這是由於c1和c2分別爲堆內存裏面兩隻貓的引用對象, 9 * 裏面裝着能夠找到這兩隻貓的地址,但因爲兩隻貓在堆內存裏面存儲在兩個不一樣的空間裏面, 10 * 因此c1和c2分別裝着不一樣的地址,所以c1和c2永遠不會相等。 11 */ 12 Cat c1 = new Cat(1, 1, 1); 13 Cat c2 = new Cat(1, 1, 1); 14 System.out.println("c1==c2的結果是:"+(c1==c2));//false 15 System.out.println("c1.equals(c2)的結果是:"+c1.equals(c2));//false 16 } 17 } 18 19 class Cat { 20 int color, weight, height; 21 22 public Cat(int color, int weight, int height) { 23 this.color = color; 24 this.weight = weight; 25 this.height = height; 26 } 27 }
程序:html
Cat c1 = new Cat(1,1,1);java
Cat c2 = new Cat(1,1,1);api
執行完以後內存之中的佈局以下圖所示,佈局
c1指向一個對象,c2也指向一個對象,c1和c2裏面裝着的是這兩隻Cat對象在堆內存裏面存儲的地址,因爲這兩隻Cat對象分別位於不一樣的存儲空間,所以c1和c2裏面裝着的地址確定不相等,所以c1和c2這兩個引用對象也確定不相等。所以執行:「System.out.println(c1==c2);」打印出來的結果確定是false。所以你new出來了兩個對象,你放心,這兩個對象的引用永遠不同,同樣的話就會把其中一個給覆蓋掉了,這個可不成。c1是否是等於c2比較的是c1和c2這兩個引用裏面裝着的內容,由於new出來的兩個對象的它們的引用永遠不同,所以c1和c2這兩個引用的內容也永遠不同,所以c1永遠不可能等於c2。所以經過比較兩個對象的引用是永遠沒法使得兩個對象相等的,如出一轍的。this
要想判斷兩個對象是否相等,不能經過比較兩個對象的引用是否相等,這是永遠都得不到相等的結果的,由於兩個對象的引用永遠不會相等,因此正確的比較方法是直接比較這兩個對象,比較這兩個對象的實質是否是同樣的,即這兩個對象裏面的內容是否是相同的,經過比較這兩個對象的屬性值是否相同而決定這兩個對象是否相等。spa
Object類提供了一個equals()方法來比較兩個對象的內容是否相同,所以咱們能夠採用這個方法去比較兩個對象是否在邏輯上「相等」。如:c1.equals(c2);這裏是調用從Object類繼承下來的equals()方法,經過查閱API文檔獲得Object類裏的equals方法的定義以下:code
public boolean equals(Object obj)htm
在Object這個類裏面提供的Equals()方法默認的實現是比較當前對象的引用和你要比較的那個引用它們指向的是不是同一個對象,即和「c1==c2」這種寫法是同樣的,「c1.equals(c2)」與「c1==c2」是徹底等價的。所以直接使用繼承下來的equals()方法也是沒法直接比較兩個對象的內容是否相同的,爲此,咱們必須得重寫equals()方法,改變這個方法默認的實現。對象
下面在Cat類裏面重寫這個繼承下來的equals()方法:blog
1 class Cat { 2 int color, weight, height; 3 4 public Cat(int color, int weight, int height) { 5 this.color = color; 6 this.weight = weight; 7 this.height = height; 8 } 9 10 /** 11 * 這裏是重寫相等從Object類繼承下來的equals()方法,改變這個方法默認的實現, 12 * 經過咱們本身定義的實現來判斷決定兩個對象在邏輯上是否相等。 13 * 這裏咱們定義若是兩隻貓的color,weight,height都相同, 14 * 那麼咱們就認爲這兩隻貓在邏輯上是如出一轍的,即這兩隻貓是「相等」的。 15 */ 16 public boolean equals(Object obj){ 17 if (obj==null){ 18 return false; 19 } 20 else{ 21 /** 22 * instanceof是對象運算符。 23 * 對象運算符用來測定一個對象是否屬於某個指定類或指定的子類的實例。 24 * 對象運算符是一個組合單詞instanceof。 25 * 該運算符是一個雙目運算符,其左邊的表達式是一個對象,右邊的表達式是一個類, 26 * 若是左邊的對象是右邊的類建立的對象,則運算結果爲true,不然爲false。 27 */ 28 if (obj instanceof Cat){ 29 Cat c = (Cat)obj; 30 if (c.color==this.color && c.weight==this.weight && c.height==this.height){ 31 return true; 32 } 33 } 34 } 35 return false; 36 } 37 }
此時在再main方法裏面執行打印的命令:
1 public static void main(String[] args) { 2 /** 3 * 這裏使用構造方法Cat()在堆內存裏面new出了兩隻貓, 4 * 這兩隻貓的color,weight,height都是同樣的, 5 * 但c1和c2卻永遠不會相等,這是由於c1和c2分別爲堆內存裏面兩隻貓的引用對象, 6 * 裏面裝着能夠找到這兩隻貓的地址,但因爲兩隻貓在堆內存裏面存儲在兩個不一樣的空間裏面, 7 * 因此c1和c2分別裝着不一樣的地址,所以c1和c2永遠不會相等。 8 */ 9 Cat c1 = new Cat(1, 1, 1); 10 Cat c2 = new Cat(1, 1, 1); 11 System.out.println("c1==c2的結果是:"+(c1==c2));//false 12 System.out.println("c1.equals(c2)的結果是:"+c1.equals(c2));//true 13 }
這一次獲得的結果就與上次沒有重寫equals()方法時獲得的結果就不同了:
「System.out.println(c1 == c2);」打印出來的結果依然是false,由於這裏是比較兩個對象的引用裏面的內容,這兩個引用裏面的內容固然不相等,並且永遠不會相等,因此打印出來的結果確定是false。
「System.out.println(c1.equals(c2));」打印出來的結果爲true,由於咱們在Cat類裏面重寫了equals()方法,改變了這個方法默認的實現,咱們把方法的實現改成只要這個兩個對象是真的存在,而且都是貓,而且它們的顏色(color),身高(height)和體重(weight)都相同,那麼這兩隻貓在邏輯上就是如出一轍的,是徹底相同的兩隻貓,即這兩隻貓是「相等」的。因此這裏打印出來的結果是true。
看下面的例子:
1 public class TestEquals { 2 3 public static void main(String args[]){ 4 String s1 = new String("hello"); 5 String s2 = new String("hello"); 6 System.out.println("s1 == s2的結果是:"+(s1 == s2));//false 7 System.out.println("s1.equals(s2)的結果是:"+s1.equals(s2));//true 8 } 9 }
這一次是比較兩個字符串對象是否相等:
System.out.println(s1 == s2);
打印出來的結果依然是fase,由於這裏比較的是s1和s2兩個字符串對象的引用,兩個對象的引用永遠不會相等,因此打印出來的結果爲false。
System.out.println(s1.equals(s2));
打印出來的結果爲true,由於在String類裏面重寫了從Object類繼承(全部的類都是從Object類繼承下來,String類固然也不例外,從父類繼承下來就擁有了父類的一切屬性與方法,因此Sting類裏面也有equals()方法,而且還把這個繼承下來的equals()方法重寫了)下來的equals()方法,改變了這個方法默認的實現,
在String類裏面是這樣重寫equals()方法的實現的:用當前的這個字符串對象和指定的字符串對象比較,指定的字符串對象不能爲空而且這個對象的字符序列和當前這個字符串對象的字符串序列同樣,若是這些條件都知足,那麼這兩個字符串對象就是相等的。
所以這裏的s2已經知足了條件,因此打印出來的結果是true。
之後在某一個類裏面比較兩個對象是否相等時,首先去API文檔裏面查找這個類是否重寫了從Object類繼承下來的equals()方法。若是重寫了equals()方法,那麼在比較兩個對象是否相等時調用的就是重寫之後的equals()方法,若是沒有重寫,那麼調用時就是直接調用從Object類裏面的繼承下來的那個equals()方法,而且採用equals()方法默認的實現去比較兩個對象是否相等。所以每個類均可以根據須要對從Object類繼承下來的equals()方法進行重寫。
對於在API文檔裏面找某個類,若是一個類不用引入包就能夠直接使用,那麼這個類確定是在java.lang這個包裏面,如這裏的String類,直接就可使用了,因此String類必定是在java.lang這個包裏面。使用某個類時看這個類引入的是哪一個包,而後就去這個包裏面找這個類,不用引入包的類必定是位於java.lang裏面,直接去java.lang裏面找就能夠了。
總結:比較兩個對象是否相等,咱們採用equals()方法,判斷兩個對象是否相等的條件是由咱們重寫equals()方法的實現後定義的,這樣就能夠比較靈活地使用equals()方法在不一樣的類裏面比較位於同一類下的兩個對象是否相等了。