一、equals方法介紹
官方文檔
1.1.通過下面的例子掌握equals的用法
public class TestEquals {
public static void main(String[] args) {
/**
* 這裏使用構造方法Cat()在堆內存裏面new出了兩隻貓,
* 這兩隻貓的color,weight,height都是一樣的,
* 但c1和c2卻永遠不會相等,這是因爲c1和c2分別爲堆內存裏面兩隻貓的引用對象,
* 裏面裝着可以找到這兩隻貓的地址,但由於兩隻貓在堆內存裏面存儲在兩個不同的空間裏面,
* 所以c1和c2分別裝着不同的地址,因此c1和c2永遠不會相等。
*/
Cat c1 = new Cat(1, 1, 1);
Cat c2 = new Cat(1, 1, 1);
System.out.println("c1==c2的結果是:"+(c1==c2));//false
System.out.println("c1.equals(c2)結果是:"+c1.equals(c2));//false
}
}
class Cat {
int color, weight, height;
public Cat(int color, int weight, int height) {
this.color = color;
this.weight = weight;
this.height = height;
}
}
1.2.畫出內存分析圖分析c1和c2比較的結果
程序:
Cat c1 = new Cat(1,1,1);
Cat c2 = new Cat(1,1,1);
執行完之後內存之中的佈局如下圖所示,
內存分佈
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。因此通過比較兩個對象的引用是永遠無法使得兩個對象相等的,一模一樣的。
要想判斷兩個對象是否相等,不能通過比較兩個對象的引用是否相等,這是永遠都得不到相等的結果的,因爲兩個對象的引用永遠不會相等,所以正確的比較方法是直接比較這兩個對象,比較這兩個對象的實質是不是一樣的,即這兩個對象裏面的內容是不是相同的,通過比較這兩個對象的屬性值是否相同而決定這兩個對象是否相等。
Object類提供了一個equals()方法來比較兩個對象的內容是否相同,因此我們可以採用這個方法去比較兩個對象是否在邏輯上“相等”。如:c1.equals(c2);這裏是調用從Object類繼承下來的equals()方法,通過查閱API文檔得到Object類裏的equals方法的定義如下:
public boolean equals(Object obj)
在Object這個類裏面提供的Equals()方法默認的實現是比較當前對象的引用和你要比較的那個引用它們指向的是否是同一個對象,即和“c1==c2”這種寫法是一樣的,“c1.equals(c2)”與“c1==c2”是完全等價的。因此直接使用繼承下來的equals()方法也是無法直接比較兩個對象的內容是否相同的,爲此,我們必須得重寫equals()方法,改變這個方法默認的實現。
下面在Cat類裏面重寫這個繼承下來的equals()方法:
class Cat {
int color, weight, height;
public Cat(int color, int weight, int height) {
this.color = color;
this.weight = weight;
this.height = height;
}
/**
* 這裏是重寫相等從Object類繼承下來的equals()方法,改變這個方法默認的實現,
* 通過我們自己定義的實現來判斷決定兩個對象在邏輯上是否相等。
* 這裏我們定義如果兩隻貓的color,weight,height都相同,
* 那麼我們就認爲這兩隻貓在邏輯上是一模一樣的,即這兩隻貓是“相等”的。
*/
public boolean equals(Object obj){
if (obj==null){
return false;
}
else{
/**
* instanceof是對象運算符。
* 對象運算符用來測定一個對象是否屬於某個指定類或指定的子類的實例。
* 對象運算符是一個組合單詞instanceof。
* 該運算符是一個雙目運算符,其左邊的表達式是一個對象,右邊的表達式是一個類,
* 如果左邊的對象是右邊的類創建的對象,則運算結果爲true,否則爲false。
*/
if (obj instanceof Cat){
Cat c = (Cat)obj;
if (c.color==this.color && c.weight==this.weight && c.height==this.height){
return true;
}
}
}
return false;
}
}
此時在再main方法裏面執行打印的命令:
public static void main(String[] args) {
/**
* 這裏使用構造方法Cat()在堆內存裏面new出了兩隻貓,
* 這兩隻貓的color,weight,height都是一樣的,
* 但c1和c2卻永遠不會相等,這是因爲c1和c2分別爲堆內存裏面兩隻貓的引用對象,
* 裏面裝着可以找到這兩隻貓的地址,但由於兩隻貓在堆內存裏面存儲在兩個不同的空間裏面,
* 所以c1和c2分別裝着不同的地址,因此c1和c2永遠不會相等。
*/
Cat c1 = new Cat(1, 1, 1);
Cat c2 = new Cat(1, 1, 1);
System.out.println("c1==c2的結果是:"+(c1==c2));//false
System.out.println("c1.equals(c2)的結果是:"+c1.equals(c2));//true
}
這一次得到的結果就與上次沒有重寫equals()方法時得到的結果就不一樣了:
“System.out.println(c1 == c2);”打印出來的結果依然是false,因爲這裏是比較兩個對象的引用裏面的內容,這兩個引用裏面的內容當然不相等,而且永遠不會相等,所以打印出來的結果肯定是false。
“System.out.println(c1.equals(c2));”打印出來的結果爲true,因爲我們在Cat類裏面重寫了equals()方法,改變了這個方法默認的實現,我們把方法的實現改爲只要這個兩個對象是真的存在,並且都是貓,並且它們的顏色(color),身高(height)和體重(weight)都相同,那麼這兩隻貓在邏輯上就是一模一樣的,是完全相同的兩隻貓,即這兩隻貓是“相等”的。所以這裏打印出來的結果是true。
1.3.如何比較兩個字符串對象是否相等?
看下面的例子:
public class TestEquals {
public static void main(String args[]){
String s1 = new String("hello");
String s2 = new String("hello");
System.out.println("s1 == s2的結果是:"+(s1 == s2));//false
System.out.println("s1.equals(s2)的結果是:"+s1.equals(s2));//true
}
}
這一次是比較兩個字符串對象是否相等:
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()方法在不同的類裏面比較位於同一類下的兩個對象是否相等了。