為什麼重寫Equals方法要重寫HashCode方法 1.Equals的作用和重寫Equals需要遵循的規則 Equals的主要作用是判斷兩個對相是否相等, Object類是所有類的父類,因此每個對象都可以使用Object的Equals相比較: public boolean equals(Objec ...
為什麼重寫Equals方法要重寫HashCode方法
1.Equals的作用和重寫Equals需要遵循的規則
Equals的主要作用是判斷兩個對相是否相等, Object類是所有類的父類,因此每個對象都可以使用Object的Equals相比較:
public boolean equals(Object obj) { return (this == obj); }
- Object類中equals方法比較的是兩個對象的引用地址,只有對象的引用地址指向同一個地址時,才認為這兩個地址是相等的,否則這兩個對象就不想等。
- 如果有兩個對象,他們需要的是這兩個對象相等,因此預設的equals()方法是不符合我們的要求的,這個時候我們就需要對equals()方法進行重寫以滿足我們的預期結果。
- 在java的集合框架中需要用到equals()方法進行查找對象,如果集合中存放的是自定義類型,並且沒有重寫equals()方法,則會調用Object父類中的equals()方法按照地址比較,往往會出現錯誤的結果,此時我們應該根據業務需求重寫equals()方法。
重寫Equals方法需要遵循的規則
- 必須定義等價關係:自反、對稱、傳遞。自反性:對於任意的對象x,x.equals(x)返回true(自己一定等於自己);對稱性:對於任意的對象x和y,若x.equals(y)為true,則y.equals(x)亦為true;傳遞性:對於任意的對象x、y和z,若x.equals(y)為true且y.equals(z)也為true,則x.equals(z)亦為true;
- 除非對象被修改,否則調用多次equals應為同樣結果:對於任意的對象x和y,x.equals(y)的第一次調用為true,那麼x.equals(y)的第二次、第三次、第n次調用也均為true,前提條件是沒有修改x也沒有修改y;
- 對於非空引用x,x.equals(null)永遠返回為false。
2.重寫hashcode的原因及重寫hashCode()方法需要遵循的協定
1.什麼是hashcode
hashcode是一個數值,主要作用是散列數據的快速存儲, Object類是所有類的父類,因此每個對象都可以使用Object的hashcode()得到對應的hash值:
public native int hashCode();
- hashCode()方法用於散列數據的快速存儲,HashSet/HashMap/Hashtable類存儲數據時都是根據存儲對象的hashcode值來進行分類存儲的,一般先根據hashcode值在集合中進行分類,在根據equals()方法判斷對象是否相同。
- HashMap對象是根據其Key的hashCode來獲取對應的Value。
- 生成一個好的hashCode值能提高HashSet查找的性能,差的hashCode值不但不能提高性能,甚至可能造成錯誤。比如hashCode方法中返回常量,會讓,HashSet的查找效率退化為List集合的查找效率;hashCode方法中返回隨機數,會讓查找結果變的不可預測。
- 好的hashCode生成方式是讓對象中的關鍵屬性與質數相乘,並將積相加獲取。
2.重寫hashcode方法的原因:
- 為了維護hashCode()方法的equals協定,該協定指出:如果根據 equals()方法,兩個對象是相等的,那麼對這兩個對象中的每個對象調用 hashCode方法都必鬚生成相同的整數結果;而兩個hashCode()返回的結果相等,兩個對象的equals()方法不一定相等。
- HashMap對象是根據其Key的hashCode來獲取對應的Value。
- 在重寫父類的equals()方法時,也重寫hashcode()方法,使相等的兩個對象獲取的HashCode值也相等,這樣當此對象做Map類中的Key時,兩個equals為true的對象其獲取的value都是同一個,比較符合實際。
3.重寫hashCode()方法需要遵循的協定
- 一致性:在Java應用程式執行期間,在對同一對象多次調用hashCode方法時,必須一致地返回相同的整數,前提是將對象進行hashcode比較時所用的信息沒有被修改。
- equals:如果根據equals()方法比較,兩個對象是相等的,那麼對這兩個對象中的每個對象調用hashCode()方法都必鬚生成相同的整數結果,等價對象必須有相同的hashcode。註:這裡說的equals()方法是指Object類中未被子類重寫過的equals()方法。
- 如果根據equals()方法比較,兩個對象不相等,那麼對這兩個對象中的任一對象上調用hashCode方法不一定生成不同的整數結果。但是,程式員應該意識到,為不相等的對象生成不同整數結果可以提高哈希表的性能。
示例代碼
學生類: Student.java
package com.java.example; import java.util.Objects; public class Student { private int age; private String name; public Student(int age, String name) { this.age = age; this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null || getClass() != obj.getClass()) { return false; } Student student = (Student) obj; return this.age == student.age && Objects.equals(this.age, student.age) && Objects.equals(this.name, student.name); } @Override public int hashCode() { return Objects.hash(this.age, this.name); } }
測試類: EqualsAndHashcode.java
package com.java.example; import java.util.HashSet; public class EqualsAndHashcode { public static void main(String[] args) { Student student1=new Student(23,"李四"); Student student2=new Student(23,"李四"); System.out.println(student1==student2); System.out.println(student1.equals(student2)); HashSet<Student> set=new HashSet<>(); set.add(student1); set.add(student2); System.out.println(student1.hashCode()); System.out.println(student2.hashCode()); System.out.println(set.size()); } }