Java中equals()方法實例詳解
equals()在哪里
首先我們知道Java中Object類是所有類的父類,它里面定義了equals()方法:
public boolean equals(Object obj) { return (this == obj); }
可以看到是使用= =來進行比較的,那么= =是什么意思呢?其實是比較兩個對象的的內(nèi)存地址。(這里順便提一下,可以去了解一下Java的堆棧。)
=》若object1.equals(object2)為true,則表示equals1和equals2實際上是引用同一個對象。
Java中重寫的equals()
這里我們看一下java的一些自帶的包裝類怎么重寫equals()的:
String.java
public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String anotherString = (String)anObject; int n = value.length; if (n == anotherString.value.length) { char v1[] = value; char v2[] = anotherString.value; int i = 0; while (n-- != 0) { if (v1[i] != v2[i]) return false; i++; } return true; } } return false; }
我們可以非常清晰的看到String的equals()方法是進行內(nèi)容比較,而不是單純的引用比較。
Integer.java
public boolean equals(Object obj) { if (obj instanceof Integer) { return value == ((Integer)obj).intValue(); } return false; }
其他的就不一一舉例了。
在Java中比較的推薦方法
所以我們一般比較基本數(shù)據(jù)類型的時候,使用"==",例如 int i = 0; if (i == 1){…},比較兩個Integer包裝類類型的時候就可以使用equals(),因為Java已經(jīng)重寫了equals()方法了。另外給出幾點建議,在java中進行比較,我們需要根據(jù)比較的類型來選擇合適的比較方式:
- 對象域,使用equals方法 。
- 類型安全的枚舉,使用equals或== 。
- 可能為null的對象域 : 使用==null 和 equals 。
- 數(shù)組域 : 使用 Arrays.equals 。
- 除float和double外的原始數(shù)據(jù)類型(int,byte等) : 使用 == 。
- float類型: 使用Float.foatToIntBits轉(zhuǎn)換成int類型,然后使用==。
- double類型: 使用Double.doubleToLongBit轉(zhuǎn)換成long類型,然后使用==。
其中6,7參考java中的對應(yīng)的包裝類實現(xiàn):
public boolean equals(Object obj) { return (obj instanceof Float) && (floatToIntBits(((Float)obj).value) == floatToIntBits(value)); } }
為什么要在我們自己的類中重寫equals()
但是有時候我們不滿足于使用基本數(shù)據(jù)類型和Java實現(xiàn)的一些繼承自O(shè)bject的哪些類,比如我們實現(xiàn)一個Person類,它是繼承自O(shè)bject類的,所以它的equals()方法默認(rèn)使用的是文章開頭提到的哪個equals()方法,當(dāng)我們使用equals()進行比較的時候,比較內(nèi)存地址,那么有可能出現(xiàn)兩個Person對象的參數(shù)都相同(比如年齡,身份證號等,在我們的實際認(rèn)知中認(rèn)為這兩個人就是一個人,應(yīng)該返回true),但是由于他們的內(nèi)存地址是不一樣的,所以equals()方法會返回false。
那么我們就需要去重寫equals()方法。
重寫equals()的規(guī)范
需要注意的是,在Java規(guī)范中,它對equals()方法的使用必須要遵循如下幾個規(guī)則:
- 自反性:對于任何非空引用值 x,x.equals(x) 都應(yīng)返回 true。
- 對稱性:對于任何非空引用值 x 和 y,當(dāng)且僅當(dāng)y.equals(x) 返回 true 時,x.equals(y) 才應(yīng)返回 true。
- 傳遞性:對于任何非空引用值 x、y 和z,如果 x.equals(y) 返回 true,并且 y.equals(z) 返回 true,那么 x.equals(z) 應(yīng)返回 true。
- 一致性:對于任何非空引用值 x 和 y,多次調(diào)用 x.equals(y) 始終返回 true 或始終返回4、一致性:對于任何非空引用值 x 和 y,多次調(diào)用 x.equals(y) 始終返回 true 或始終返回false,前提是對象上 equals 比較中所用的信息沒有被修改
- 對于任何非空引用值 x,x.equals(null) 都應(yīng)返回false。
重寫equals()可能的誤區(qū)
查看下述代碼:
public class TestEquals { public static void main(String[] args) { Employee employee = new Employee("mily",1); Employee employee2 = new Employee("mily",2); Person p1 = new Person("mily"); System.out.println(p1.equals(employee)); System.out.println(p1.equals(employee2)); System.out.println(employee.equals(employee2)); } } class Person { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public Person(String name) { this.name = name; } @Override public boolean equals(Object obj) { if (obj instanceof Person) { Person person = (Person) obj; if (person.getName() == null | name == null) { return false; } else { return name.equalsIgnoreCase(person.getName()); } } return false; } } 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; } @Override public boolean equals(Object obj) { if (obj instanceof Employee) { Employee employee = (Employee) obj; return super.equals(obj) && employee.getId() == id; } return false; } }
輸出:
true
true
false
上述代碼中,我定義了一個Person類,有一個屬性name;還定義了一個Employee類,它是Person的子類,多出一個id的屬性;在測試代碼中“new”出了三個對象:
- name為mily,id為1的一個職員 —— employee
- name為mily,id為2的職員 —— employee2
- name為mily的一個普通人 —— p1
在大家的認(rèn)知下,應(yīng)該是三者都不是“equal”的,但是在執(zhí)行 p1.equals(employee)時返回的是true,仔細(xì)看了代碼之后你就會發(fā)現(xiàn)問題所在,代碼把employee當(dāng)成一個Person對象去執(zhí)行equals方法了,比較了name發(fā)現(xiàn)一樣,就認(rèn)為是“equal”了,這是一種很常見的誤區(qū)。
一般的equals()寫法
下面給出一個完美的 equals 方法的建議:
1、顯示參數(shù)命名為 otherObject,稍后會將它轉(zhuǎn)換成另一個叫做 other 的變量。
2、判斷比較的兩個對象引用是否相等,如果引用相等那么表示是同一個對象,那么當(dāng)然相等
3、如果 otherObject 為 null,直接返回false,表示不相等
4、比較 this 和 otherObject 是否是同一個類:如果 equals 的語義在每個子類中有所改變,就使用 getClass 檢測;如果所有的子類都有統(tǒng)一的定義,那么使用 instanceof 檢測
5、將 otherObject 轉(zhuǎn)換成對應(yīng)的類類型變量
6、最后對對象的屬性進行比較。使用 == 比較基本類型,使用 equals 比較對象。如果都相等則返回true,否則返回false。注意如果是在子類中定義equals,則要包含 super.equals(other)
按照上述的equals()規(guī)范,我的實現(xiàn)如下:
public class TestEquals2 { public static void main(String[] args) { Employee employee = new Employee("mily",1); Employee employee2 = new Employee("mily",1); Person p1 = new Person("mily"); System.out.println(p1.equals(employee)); System.out.println(p1.equals(employee2)); System.out.println(employee.equals(employee2)); Employee employee3 = new Employee(null,1); Employee employee4 = new Employee(null,1); Person p2 = new Person(null); System.out.println(p2.equals(employee3)); System.out.println(p2.equals(employee4)); System.out.println(employee3.equals(employee4)); } } class Person { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public Person(String name) { this.name = name; } @Override public boolean equals(Object obj) { if(this == obj){ return true; } if(obj == null || getClass() != obj.getClass()){ return false; } Person person = (Person) obj; if(person.getName() == null | name == null) { return false; } else { return name.equalsIgnoreCase(person.getName()); } } } 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; } @Override public boolean equals(Object obj) { if(this == obj){ return true; } if(obj == null || getClass() != obj.getClass()){ return false; } Employee employee = (Employee) obj; if(employee.getName() == null | getName() == null) { return false; }else { return getName().equalsIgnoreCase(employee.getName()) && employee.getId() == id; } } }
結(jié)果:
false
false
true
false
false
false
附:java中equals()方法的正確使用
在Java中比較兩個字符串是否相等,想必只要不是初學(xué)者都知道用equals()方法來進行比較,但是實際上很多時候都用錯了。
就我自己開發(fā)而言,加入比較一個String s的內(nèi)容是否是"aaa"時,往往會寫成如下代碼:
if(s.equals("aaa")){ ... }
乍一看沒什么問題,直到我裝了Alibaba Coding Guidelines 這個插件,一檢查,就告訴我這樣不對了。
為什么呢?因為很多情況下,并不能保證字符串s是不是為null,即直接這么判斷,很容易產(chǎn)生空指針異常的錯誤,因此正確的使用方法應(yīng)該是:
"aaa".equals(s);
總結(jié)
到此這篇關(guān)于Java中equals()方法的文章就介紹到這了,更多相關(guān)Java?equals()方法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
解決Spring boot整合mybatis,xml資源文件放置及路徑配置問題
這篇文章主要介紹了解決Spring boot整合mybatis,xml資源文件放置及路徑配置問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-12-12java使用TimeZone將中國標(biāo)準(zhǔn)時間轉(zhuǎn)成時區(qū)值
這篇文章主要介紹了java使用TimeZone將中國標(biāo)準(zhǔn)時間轉(zhuǎn)成時區(qū)值的相關(guān)資料,需要的朋友可以參考下2023-11-11Java畢業(yè)設(shè)計實戰(zhàn)項目之倉庫管理系統(tǒng)的實現(xiàn)流程
這是一個使用了java+SSM+Maven+Bootstrap+mysql開發(fā)的倉庫管理系統(tǒng),是一個畢業(yè)設(shè)計的實戰(zhàn)練習(xí),具有一個倉庫管理系統(tǒng)該有的所有功能,感興趣的朋友快來看看吧2022-01-01Idea中如何調(diào)出Run dashboard 或services窗口
這篇文章主要介紹了Idea中如何調(diào)出Run dashboard 或services窗口問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-03-03Java通過httpclient比較重定向和請求轉(zhuǎn)發(fā)
這篇文章主要介紹了Java通過httpclient比較重定向和請求轉(zhuǎn)發(fā),HttpClient?4.x?版本,get請求方法會自動進行重定向,而post請求方法不會自動進行重定向,需要的朋友可以參考下2023-04-04java文件復(fù)制代碼片斷(java實現(xiàn)文件拷貝)
本文介紹java實現(xiàn)文件拷貝的代碼片斷,大家可以直接放到程序里運行2014-01-01Java 實戰(zhàn)項目錘煉之醫(yī)院門診收費管理系統(tǒng)的實現(xiàn)流程
讀萬卷書不如行萬里路,只學(xué)書上的理論是遠(yuǎn)遠(yuǎn)不夠的,只有在實戰(zhàn)中才能獲得能力的提升,本篇文章手把手帶你用java+html+jdbc+mysql實現(xiàn)一個醫(yī)院門診收費管理系統(tǒng),大家可以在過程中查缺補漏,提升水平2021-11-11