Java equals()和hashCode()
介紹:
Java Object類提供了方法的基本實現(xiàn)– hashCode()和equals()。 這些方法非常有用,尤其是在使用Collection框架時。 哈希表實現(xiàn)依賴于這些方法來存儲和檢索數(shù)據(jù)。
在本教程中,我們將學(xué)習(xí)hashCode()和equals()之間的協(xié)定(它們的默認(rèn)實現(xiàn))。 我們還將討論何時以及如何覆蓋這些方法。
默認(rèn)行為:
首先讓我們看一下這些方法的默認(rèn)實現(xiàn):
存在于Object類中的equals()方法只是比較對象引用:
public boolean equals(Object obj) {return (this == obj); }因此,默認(rèn)情況下, obj1.equals(obj2)與obj1 == obj2相同。
equals()方法比較諸如String等的類的實際值,因為它們在相應(yīng)的類中被覆蓋。
JDK中hashCode()方法的簽名為:
public native int hashCode();在這里, native關(guān)鍵字表示該方法是使用JNI (Java本機(jī)接口)以本機(jī)代碼實現(xiàn)的。
hashCode()方法返回一個int類型。 默認(rèn)情況下,返回值表示對象存儲器地址。
實施原則:
在覆蓋equals()和hashCode()方法之前,我們先來看一下準(zhǔn)則:
1. equals(): ? 我們對equals()方法的實現(xiàn)必須是:
- 反身:對于任何參考值obj , obj.equals(obj)應(yīng)該返回true
- 對稱:對于參考值obj1和obj2 ,如果obj1.equals(obj2)為true,則obj2.equals(obj2)也應(yīng)返回true
- 傳遞性:對于值OBJ1參考,OBJ 2和 OBJ 3,如果obj1.equals(OBJ 2) 真實 ,obj2.equals(OBJ 3)為真 ,那么obj1.equals(OBJ 3)也應(yīng)該返回true
- 一致:只要我們沒有更改實現(xiàn), equals()方法的多次調(diào)用必須始終返回相同的值
2. hashCode():實現(xiàn)hashCode()時,必須考慮以下幾點(diǎn):
- 在一次執(zhí)行中, hashCode()的多次調(diào)用必須返回相同的值,前提是我們不更改equals()實現(xiàn)中的屬性
- 相等的對象必須返回相同的hashCode()值
- 兩個或更多不相等的對象可以具有相同的hashCode()值
盡管在覆蓋這些方法時要牢記上述所有原則,但是其中有一個流行的規(guī)則:
對于兩個對象obj1和obj2 ,
- 如果obj1.equals(obj2),則obj1.hashCode()= obj2.hashCode()必須為true
- 但是,如果obj1.hashCode()== obj2.hashCode() ,則obj1.equals(obj2)可以返回true或false,即obj1和obj2可能相等或不相等
這通常被稱為equals()和hashCode()契約。
為什么覆蓋
hashCode()和equals()方法在基于哈希表的實現(xiàn)中存儲和檢索元素方面起著重要作用。 hashCode()確定給定項映射到的存儲桶。 在存儲桶中, equals()方法用于查找給定的條目。
假設(shè)我們有一個Employee類:
public class Employee {private int id;private String name;//constructors, getters, setters, toString implementations}還有一個存儲Employee作為鍵的HashMap :
Map<Employee, Integer> map = new HashMap<>();map.put(new Employee(1, "Sam"), 1); map.put(new Employee(2, "Sierra"), 2);現(xiàn)在我們已經(jīng)插入了兩個條目,讓我們嘗試一個containsKey()檢查:
boolean containsSam = map.containsKey(new Employee(1, "Sam")); //false盡管我們有Sam的條目,但是containsKey()返回false 。 這是因為我們尚未覆蓋equals()和hashCode()方法。 默認(rèn)情況下, equals()只會進(jìn)行基于引用的比較。
覆蓋
根據(jù)Javadocs:
當(dāng)我們覆蓋equals()方法時,我們還必須覆蓋hashCode()方法。
這將有助于避免違反equals-hashCode合同。
請注意,如果我們違反合同,編譯器不會抱怨,但是當(dāng)我們將此類對象作為鍵存儲在HashMap中時,最終可能會遇到意外行為。
我們可以使用IDE的功能快速覆蓋這些方法。 使用Eclipse時,我們可以轉(zhuǎn)到Source-> Generate hashCode()和equals()。 讓我們看看為Employee類生成的實現(xiàn):
public class Employee {...@Overridepublic int hashCode() {final int prime = 31;int result = 1;result = prime * result + id;result = prime * result + ((name == null) ? 0 : name.hashCode());return result;}@Overridepublic boolean equals(Object obj) {if (this == obj)return true;if (obj == null)return false;if (getClass() != obj.getClass())return false;Employee other = (Employee) obj;if (id != other.id)return false;if (name == null) {if (other.name != null)return false;} else if(!name.equals(other.name))return false;return true;} }顯然,相同的字段已用于實現(xiàn)equals()和hashCode()方法,以與合同保持一致。
最佳做法:
使用equals()和hashCode()時應(yīng)遵循的一些最佳實踐包括:
- 實現(xiàn)hashCode()以在各個存儲桶之間平均分配項目。 這樣做的目的是最大程度地減少碰撞次數(shù),從而獲得良好的性能
- 對于equals()和hashCode()實現(xiàn),我們應(yīng)該使用相同的字段
- 在HashMap中將不可變對象作為鍵,因為它們支持緩存哈希碼值
- 使用ORM工具時,請始終使用getter代替hashCode()和equals()方法定義中的字段。 那是因為有些字段可能是延遲加載的
結(jié)論:
在本教程中,我們首先研究了equals()和hashCode()方法的默認(rèn)實現(xiàn)。 稍后,我們討論了何時以及如何覆蓋這些方法。
成為第一個發(fā)表評論的人。
翻譯自: https://www.javacodegeeks.com/2019/05/java-equals-hashcode.html
總結(jié)
以上是生活随笔為你收集整理的Java equals()和hashCode()的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java 8 新功能详解_Java 8的
- 下一篇: java美元兑换,(Java实现) 美元