Java重寫equals方法時為什麼要重寫hashcode方法
equals 方法和 hashcode 方法沒有必然關係,並不是說重寫 equals 方法就一定要重寫 hashcode 方法。 用途不同, equals 用來比較兩個物件是否相等,在大多數 JDK 的集合類中判斷唯一性的時候使用的都是 equals 方法。而 hashcode 方法用來計算物件的 Hash 值,基於 Hash 演算法存放資料的集合會用到,比如 HashMap、HashSet。 equals 方法很好理解,區別於直接比較物件記憶體地址的 == ,它被設計為用來比較物件內容語義上的相等。 而要理解 hashcode 方法,首先你要知道什麼是雜湊演算法,瞭解一下 HashMap 底下的儲存結構和存放讀取資料的過程(對 key 呼叫 hashcode 得雜湊值,找到該雜湊值對應的桶,往桶裡放 value)。你可以認為 hashcode 是為了給物件分類用的。
重寫hashCode()時最重要的原因就是:無論何時,對同一個物件呼叫hashCode()都應該生成同樣的值。如果在將一個物件用put()方法添 加進HashMap時產生一個hashCode()值,而用get()取出時卻產生了另外一個 hashCode()值,那麼就無法重新取得該物件了。所以,如果你的hashCode()方法依賴於物件中易變的資料,那使用者就要小心了,因為此資料發 生變化時,hashCode()就會產生一個不同的hash碼,相當於產生了一個不同的“鍵”。 Object的hashCode()方法,返回的是當前物件的記憶體地址。下次如果我們需要取一個一樣的“鍵”對應的鍵值對的時候,我們就無法得到一樣的 hashCode值了。因為我們後來建立的“鍵”物件已經不是存入HashMap中的那個記憶體地址的物件了。 我們看一個簡單的例子,就能更加清楚的理解上面的意思。假定我們寫了一個類:Person (人),我們判斷一個物件“人”是否指向同一個人,只要知道這個人的身份證號一直就可以了。 先來個沒有重寫Code類的hashcode()的例子吧,看看是什麼效果:
- package com.fit;
- import java.util.HashMap;
- /**
- * 身份證類
- *
- * @author ZYD
- *
- */
- public class Code {
- /**
- * 身份證號碼,一旦確定就不能更改
- */
- private final int id;
- public int getId() {
- return id;
- }
- /**
- * 通過構造方法確定身份證號碼
- *
- * @param id
- */
- public Code(int id) {
- this.id = id;
- }
- /**
- * 重寫equals()方法
- */
- public boolean equals(Object o) {
- // 如果地址一樣,則兩個物件相同
- if (this == o) {
- return true;
- }
- // 如果兩個物件是同一型別,則比較其屬性值是否都相同。如果都相同,則說明兩個物件也相同;否則,說明這兩個物件不相同。
- if (o instanceof Code) {
- Code co = (Code) o;
- boolean b = (co.id == this.id);
- return b;
- }
- return false;
- }
- /**
- * 重寫toString()方法
- */
- public String toString() {
- return "【身份證】:" + id;
- }
- /**
- * 測試
- * @param args
- */
- public static void main(String[] args) {
- HashMap<Code, Person> map = new HashMap<Code, Person>();
- Person p1 = new Person(new Code(10001),"張三");
- Person p2 = new Person(new Code(10002),"李四");
- map.put(p1.getCode(), p1);
- map.put(p2.getCode(), p2);
- System.out.println("HashMap 中存放的人員資訊:\n"+map);
- //張三改名為張山,身份證號不變。
- Person p3 = new Person(new Code(10001),"張山");
- map.put(p3.getCode(), p3);
- System.out.println("張三改名為張山後 HashMap 中存放的人員資訊:\n"+map);
- //查詢身份證為10001 的人員資訊
- System.out.println("查詢身份證為:10001 的人員資訊:"+map.get(new Code(10001)));
- }
- }
- /**
- * 人類
- * @author Administrator
- *
- */
- class Person {
- /**
- * 每一個成人都有一個身份證
- */
- private Code code;
- /**
- * 姓名
- */
- private String name;
- public Code getCode() {
- return code;
- }
- public void setCode(Code code) {
- this.code = code;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public Person() {
- }
- public Person(Code code, String name) {
- this.code = code;
- this.name = name;
- }
- /**
- * 重寫equals()方法 當兩個人得身份證號相同以及姓名相同時,表示這兩個人是同一個人。
- */
- public boolean equals(Object o) {
- if (o == this) {
- return true;
- }
- if (o instanceof Person) {
- Person p = (Person) o;
- boolean b = this.code.equals(p.code) && this.name.equals(p.name);
- return b;
- }
- return false;
- }
- /**
- * 重寫toString()方法
- */
- public String toString() {
- return "【姓名】:" + name + " ";
- }
- }
執行結果:
HashMap 中存放的人員資訊: {【身份證】:10002=【姓名】:李四 , 【身份證】:10001=【姓名】:張三 } 張三改名為張山後 HashMap 中存放的人員資訊: {【身份證】:10002=【姓名】:李四 , 【身份證】:10001=【姓名】:張三 , 【身份證】:10001=【姓名】:張山 } 查詢身份證為:10001 的人員資訊:null
從上面的結果可以看出:
我們所做的更新和查詢操作都失敗了。失敗的原因就是我們的身份證類: Code 沒有覆寫 hashCode() 方法。這個時候,當查詢一樣的身份證號碼的鍵值對的時候,使用的是預設的物件的記憶體地址來進行定位。這樣,後面的所有的身份證號物件
new Code(10001) 產生的 hashCode () 值都是不一樣的,所以導致操作失敗。
重寫Code類的hashcode(),程式碼上:
- package com.fit;
- import java.util.HashMap;
- /**
- * 身份證類
- *
- * @author ZYD
- *
- */
- public class Code {
- /**
- * 身份證號碼,一旦確定就不能更改
- */
- private final int id;
- public int getId() {
- return id;
- }
- /**
- * 通過構造方法確定身份證號碼
- *
- * @param id
- */
- public Code(int id) {
- this.id = id;
- }
- /**
- * 重寫equals()方法
- */
- public boolean equals(Object o) {
- // 如果地址一樣,則兩個物件相同
- if (this == o) {
- return true;
- }
- // 如果兩個物件是同一型別,則比較其屬性值是否都相同。如果都相同,則說明兩個物件也相同;否則,說明這兩個物件不相同。
- if (o instanceof Code) {
- Code co = (Code) o;
- boolean b = (co.id == this.id);
- return b;
- }
- return false;
- }
- /**
- * 重寫hashcode()方法,以身份證號碼作為hash碼。
- *
- * @return
- */
- public int hashCode() {
- return id;
- }
- /**
- * 重寫toString()方法
- */
- public String toString() {
- return "【身份證】:" + id;
- }
- /**
- * 測試
- * @param args
- */
- public static void main(String[] args) {
- HashMap<Code, Person> map = new HashMap<Code, Person>();
- Person p1 = new Person(new Code(10001),"張三");
- Person p2 = new Person(new Code(10002),"李四");
- map.put(p1.getCode(), p1);
- map.put(p2.getCode(), p2);
- System.out.println("HashMap 中存放的人員資訊:\n"+map);
- //張三改名為張山,身份證號不變。
- Person p3 = new Person(new Code(10001),"張山");
- map.put(p3.getCode(), p3);
- System.out.println("張三改名為張山後 HashMap 中存放的人員資訊:\n"+map);
- //查詢身份證為10001 的人員資訊
- System.out.println("查詢身份證為:10001 的人員資訊:"+map.get(new Code(10001)));
- }
- }
- /**
- * 人類
- * @author Administrator
- *
- */
- class Person {
- /**
- * 每一個成人都有一個身份證
- */
- private Code code;
- /**
- * 姓名
- */
- private String name;
- public Code getCode() {
- return code;
- }
- public void setCode(Code code) {
- this.code = code;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public Person() {
- }
- public Person(Code code, String name) {
- this.code = code;
- this.name = name;
- }
- /**
- * 重寫equals()方法 當兩個人得身份證號相同以及姓名相同時,表示這兩個人是同一個人。
- */
- public boolean equals(Object o) {
- if (o == this) {
- return true;
- }
- if (o instanceof Person) {
- Person p = (Person) o;
- boolean b = this.code.equals(p.code) && this.name.equals(p.name);
- return b;
- }
- return false;
- }
- /**
- * 重寫toString()方法
- */
- public String toString() {
- return "【姓名】:" + name + " ";
- }
- }
相關文章
- java為什麼要重寫hashCode和equals方法Java
- 重寫equals()方法時,需要同時重寫hashCode()方法
- 重寫equals()時為什麼也得重寫hashCode()之深度解讀equals方法與hashCode方法淵源
- 為什麼重寫 equals() 方法,一定要重寫 hashCode() 呢?| HashMapHashMap
- java 中為什麼重寫 equals 後需要重寫 hashCodeJava
- 為什麼重寫equals必須重寫hashCode
- 建議重寫equals方法時也一併重寫hashCode方法
- 重寫Object.equals()方法和Object.hashCode()方法Object
- 關於重寫equals()和hashCode()的思考
- java 方法重寫概念Java
- hashcode重寫
- java 新建立的類要重寫的方法Java
- java之方法的重寫Java
- 關於HashMap的key重寫hashcode和equals的理解HashMap
- Java中方法重寫與方法過載Java
- java方法的神奇修改(重寫)Java
- 搞懂 Java equals 和 hashCode 方法Java
- Dubbo為什麼要用Go重寫?Go
- 方法重寫(Override)IDE
- 寫在平臺大戰之後:為什麼我要重寫自己的UIKit?UI
- Java基礎系列-equals方法和hashCode方法Java
- Java 面試題關於方法的重寫Java面試題
- 複習java面對物件(方法重寫)Java物件
- 第9條:覆蓋equals時總要覆蓋hashCode方法
- HashSet中重寫haseCode和equals
- 細說equals()方法和hashCode()方法
- 詳解equals()方法和hashCode()方法
- 【iOS】category重寫方法的呼叫iOSGo
- 重寫Java的String及其大部分方法Java
- 二、Java初級--8、繼承和重寫方法Java繼承
- Java 重寫方法與初始化的隱患Java
- JavaBean重寫Object類中的方法JavaBeanObject
- 方法重置和重寫的區別
- Java 物件的雜湊值是每次 hashCode() 方法呼叫重計算麼?Java物件
- hashCode()方法對於HashSet是不是十分重要
- String的equals和hashCode方法
- 自動生成hashcode和equals方法
- python繼承和重寫init方法Python繼承