Java基础篇:equals()方法与==的区别
1、超類Object的equals()底層原理:
在Object超類中已經提供了equals()方法,源碼如下:
public boolean equals(Object obj) { return (this == obj); }所有的對象都擁有標識(內存地址)和狀態(數據),同時“==”比較的是兩個對象的內存地址,在Object的equals()底層調用的是==號,所以說Object的equals()是比較兩個對象的內存地址是否相等,如果為true,則表示的引用的是同一個對象。
2、equals()與 ==?的區別:
(1)== 號在比較基本數據類型時比較的是數據的值,而比較引用類型時比較的是兩個對象的地址值;
(2)equals()不能用于基本的數據類型,對于基本的數據類型要用其包裝類。
(3)默認情況下,從Object繼承而來的 equals 方法與 “==” 是完全等價的,比較的都是對象的內存地址,因為底層調用的是 “==” 號,但我們可以重寫equals方法,使其按照我們的需求方式進行比較,如String類重寫equals()方法,使其比較的是字符的內容,而不再是內存地址。
3、equals()的重寫規則:
-
自反性。對于任何非null的引用值x,x.equals(x)應返回true。
-
對稱性。對于任何非null的引用值x與y,當且僅當:y.equals(x)返回true時,x.equals(y)才返回true。
-
傳遞性。對于任何非null的引用值x、y與z,如果y.equals(x)返回true,y.equals(z)返回true,那么x.equals(z)也應返回true。
-
一致性。對于任何非null的引用值x與y,假設對象上equals比較中的信息沒有被修改,則多次調用x.equals(y)始終返回true或者始終返回false。
-
對于任何非空引用值x,x.equal(null)應返回false。
4、有關equals()與 == 號的小例子:
public class Test {public static void main(String[] args) { String str1 = new String("abc");String str2 = new String("abc");System.out.println(str1 == str2);//falseSystem.out.println(str1.equals(str2));//trueString str3 = "123";String str4 = "123";System.out.println(str3 == str4);//trueSystem.out.println(str3.equals(str4));//true } }根據上面的demo輸出結果可以看到,前面的輸出結果是false、true,后面的輸出結果是true、true。為什么兩次==的輸出結果不一樣呢?這其實涉及到了內存中的常量池,常量池屬于方法區的一部分,當運行到創建str3對象時,如果常量池中沒有“123”,則在常量池中創建一個"123"對象,運行到str4對象時,由于“123”已經存在常量池,就直接使用,所以str3和str4對象其實是同一個對象,他們的地址引用相同。
而對于str1和str2,它們其實創建了兩次對象,一次在常量池創建了對象“abc”,所以str1和str2的地址值是不相等的。
5、重寫equals()中 getClass 與 instaceof 的區別:
在重寫equals()?方法時,一般都是推薦使用 getClass 來進行類型判斷,不是使用 instanceof(除非所有的子類有統一的語義才使用instanceof)。我們都知道 instanceof 的作用是判斷其左邊對象是否為其右邊類的實例,返回 boolean 類型的數據,可以用來判斷繼承中的子類的實例是否為父類的實現。
下來我們來看一個例子:父類Person
public class Person {protected String name;public String getName() {return name;}public void setName(String name) {this.name = name;}public Person(String name){this.name = name;}public boolean equals(Object object){if(object instanceof Person){Person p = (Person) object;if(p.getName() == null || name == null){return false;}else{return name.equalsIgnoreCase(p.getName ());}}return false;}}子類 Employee:
public class Employee extends Person{private int id;public int getId() {return id;}public void setId(int id) {this.id = id;}public Employee(String name,int id){super(name);this.id = id;}/*** 重寫equals()方法*/public boolean equals(Object object){if(object instanceof Employee){Employee e = (Employee) object;return super.equals(object) && e.getId() == id;}return false;}}上面父類 Person 和子類 Employee 都重寫了 equals(),不過 Employee 比父類多了一個id屬性,而且這里我們并沒有統一語義。測試代碼如下:
public class Test {public static void main(String[] args) {Employee e1 = new Employee("employee", 23);Employee e2 = new Employee("employee", 24);Person p1 = new Person("employee");System.out.println(p1.equals(e1));//trueSystem.out.println(p1.equals(e2));//trueSystem.out.println(e1.equals(e2));//false}}上面代碼我們定義了兩個員工和一個普通人,雖然他們同名,但是他們肯定不是同一人,所以按理來說結果應該全部是 false,但是事與愿違,結果是:true、true、false。對于那 e1!=e2 我們非常容易理解,因為他們不僅需要比較 name,還需要比較 ID。但是 p1 即等于 e1 也等于 e2,這是非常奇怪的,因為 e1、e2 明明是兩個不同的類,但為什么會出現這個情況?首先 p1.equals(e1),是調用 p1 的 equals 方法,該方法使用 instanceof 關鍵字來檢查 e1 是否為 Person 類,這里我們再看看 instanceof:判斷其左邊對象是否為其右邊類的實例,也可以用來判斷繼承中的子類的實例是否為父類的實現。他們兩者存在繼承關系,肯定會返回 true 了,而兩者 name 又相同,所以結果肯定是 true。所以出現上面的情況就是使用了關鍵字 instanceof,這是非常容易導致我們“鉆牛角尖”。故在覆寫 equals 時推薦使用 getClass 進行類型判斷。而不是使用 instanceof(除非子類擁有統一的語義)。?
總結
以上是生活随笔為你收集整理的Java基础篇:equals()方法与==的区别的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java基础篇:对象拷贝:clone方法
- 下一篇: Java基础篇:String、Strin