java中的hashcode有什么用 hashCode方法的3個(gè)重寫(xiě)原則

hashcode在Java中主要用于快速比較對(duì)象是否相等,尤其是在集合類如hashmap、hashset中,通過(guò)hashcode可以大幅提升查找效率。1. 一致性:只要對(duì)象的屬性沒(méi)有改變,無(wú)論調(diào)用多少次hashcode方法,都應(yīng)該返回相同的值;2. 相等性:如果兩個(gè)對(duì)象通過(guò)equals方法比較是相等的,那么它們的hashcode值必須相等;3. 不等性:如果兩個(gè)對(duì)象通過(guò)equals方法比較是不相等的,它們的hashcode值最好也不同,這樣可以提高哈希表的性能,減少?zèng)_突。hashcode和equals的關(guān)系是:若兩個(gè)對(duì)象相等(equals返回true),則它們的hashcode必須相同;但若hashcode相同,它們不一定相等。如果不重寫(xiě)hashcode,可能導(dǎo)致使用哈希表時(shí)出現(xiàn)邏輯錯(cuò)誤,例如內(nèi)容相同但hashcode不同的對(duì)象會(huì)被視為不同鍵。最佳實(shí)踐包括:基于關(guān)鍵屬性生成hashcode、避免使用可變屬性、使用objects.hash()方法、考慮性能、進(jìn)行單元測(cè)試驗(yàn)證正確性。只有在對(duì)象永遠(yuǎn)不會(huì)放入哈希表、對(duì)象不可變且未重寫(xiě)equals、或性能要求極高時(shí),才可以不重寫(xiě)hashcode方法,否則始終應(yīng)重寫(xiě)以確保程序正確性和性能。

java中的hashcode有什么用 hashCode方法的3個(gè)重寫(xiě)原則

hashCode在Java中主要用于快速比較對(duì)象是否相等,尤其是在集合類如HashMap、HashSet中,通過(guò)hashCode可以大幅提升查找效率。簡(jiǎn)單來(lái)說(shuō),hashCode就像是對(duì)象的指紋,可以快速定位對(duì)象。

java中的hashcode有什么用 hashCode方法的3個(gè)重寫(xiě)原則

hashCode方法的3個(gè)重寫(xiě)原則是:

java中的hashcode有什么用 hashCode方法的3個(gè)重寫(xiě)原則

  1. 一致性: 只要對(duì)象的屬性沒(méi)有改變,無(wú)論調(diào)用多少次hashCode方法,都應(yīng)該返回相同的值。
  2. 相等性: 如果兩個(gè)對(duì)象通過(guò)equals方法比較是相等的,那么它們的hashCode值必須相等。
  3. 不等性: 如果兩個(gè)對(duì)象通過(guò)equals方法比較是不相等的,它們的hashCode值最好也不同,這樣可以提高哈希表的性能,減少?zèng)_突。

hashCode和equals方法到底是什么關(guān)系?

立即學(xué)習(xí)Java免費(fèi)學(xué)習(xí)筆記(深入)”;

java中的hashcode有什么用 hashCode方法的3個(gè)重寫(xiě)原則

hashCode和equals方法是Java中用于比較對(duì)象是否相等的兩個(gè)重要方法。它們之間的關(guān)系是:如果兩個(gè)對(duì)象相等(equals方法返回true),那么它們的hashCode值必須相等。反過(guò)來(lái),如果兩個(gè)對(duì)象的hashCode值相等,它們不一定相等(equals方法可能返回false)。

這個(gè)關(guān)系非常重要,尤其是在使用哈希表(如HashMap、HashSet)時(shí)。哈希表通過(guò)hashCode值來(lái)快速定位對(duì)象,如果兩個(gè)相等的對(duì)象的hashCode值不同,那么在哈希表中就可能出現(xiàn)邏輯錯(cuò)誤。

舉個(gè)例子,假設(shè)你有一個(gè)自定義的類Person,并且重寫(xiě)了equals方法,只比較name和age屬性。如果你沒(méi)有重寫(xiě)hashCode方法,那么即使兩個(gè)Person對(duì)象的name和age相同,它們的hashCode值也可能不同,因?yàn)槟J(rèn)的hashCode方法是基于對(duì)象的內(nèi)存地址生成的。

class Person {     String name;     int age;      public Person(String name, int age) {         this.name = name;         this.age = age;     }      @Override     public boolean equals(Object obj) {         if (this == obj) return true;         if (obj == NULL || getClass() != obj.getClass()) return false;         Person person = (Person) obj;         return age == person.age && Objects.equals(name, person.name);     }      // 缺少 hashCode 方法 }  public class Main {     public static void main(String[] args) {         Person p1 = new Person("Alice", 30);         Person p2 = new Person("Alice", 30);          System.out.println(p1.equals(p2)); // true         System.out.println(p1.hashCode() == p2.hashCode()); // 很有可能 false,因?yàn)闆](méi)有重寫(xiě)hashCode     } }

在這種情況下,如果你將p1和p2放入HashSet中,HashSet會(huì)認(rèn)為它們是兩個(gè)不同的對(duì)象,因?yàn)樗鼈兊膆ashCode值不同,即使它們的name和age相同。這顯然是不符合預(yù)期的。

因此,當(dāng)你重寫(xiě)equals方法時(shí),一定要同時(shí)重寫(xiě)hashCode方法,以保證相等的對(duì)象具有相同的hashCode值。一個(gè)簡(jiǎn)單的hashCode方法實(shí)現(xiàn)可以使用Objects.hash():

import java.util.Objects;  class Person {     String name;     int age;      public Person(String name, int age) {         this.name = name;         this.age = age;     }      @Override     public boolean equals(Object obj) {         if (this == obj) return true;         if (obj == null || getClass() != obj.getClass()) return false;         Person person = (Person) obj;         return age == person.age && Objects.equals(name, person.name);     }      @Override     public int hashCode() {         return Objects.hash(name, age);     } }  public class Main {     public static void main(String[] args) {         Person p1 = new Person("Alice", 30);         Person p2 = new Person("Alice", 30);          System.out.println(p1.equals(p2)); // true         System.out.println(p1.hashCode() == p2.hashCode()); // true,因?yàn)橹貙?xiě)了hashCode     } }

重寫(xiě)hashCode方法時(shí)有哪些最佳實(shí)踐?

重寫(xiě)hashCode方法需要遵循一些最佳實(shí)踐,以確保其性能和正確性:

  1. 使用對(duì)象的關(guān)鍵屬性: hashCode方法應(yīng)該基于對(duì)象中用于equals方法比較的關(guān)鍵屬性來(lái)生成hashCode值。這意味著如果兩個(gè)對(duì)象的這些關(guān)鍵屬性相同,那么它們的hashCode值也應(yīng)該相同。
  2. 避免使用可變屬性: 盡量避免使用可變屬性來(lái)生成hashCode值。如果對(duì)象的hashCode值在其生命周期內(nèi)發(fā)生改變,那么在使用哈希表時(shí)可能會(huì)導(dǎo)致問(wèn)題。
  3. 使用Objects.hash(): Java 7引入了Objects.hash()方法,可以方便地為多個(gè)屬性生成hashCode值。這個(gè)方法可以處理null值,并且可以生成一個(gè)相對(duì)均勻分布的hashCode值。
  4. 考慮性能: hashCode方法的性能也很重要,因?yàn)樗鼤?huì)被頻繁調(diào)用。避免在hashCode方法中進(jìn)行復(fù)雜的計(jì)算或IO操作。
  5. 測(cè)試hashCode方法: 編寫(xiě)單元測(cè)試來(lái)驗(yàn)證hashCode方法的正確性。確保相等的對(duì)象具有相同的hashCode值,并且hashCode值在對(duì)象的生命周期內(nèi)不會(huì)發(fā)生改變。

舉個(gè)例子,假設(shè)你有一個(gè)自定義的類Product,它有name、price和description三個(gè)屬性。其中,只有name和price用于equals方法比較。那么,你可以這樣重寫(xiě)hashCode方法:

import java.util.Objects;  class Product {     String name;     double price;     String description;      public Product(String name, double price, String description) {         this.name = name;         this.price = price;         this.description = description;     }      @Override     public boolean equals(Object obj) {         if (this == obj) return true;         if (obj == null || getClass() != obj.getClass()) return false;         Product product = (Product) obj;         return Double.compare(product.price, price) == 0 && Objects.equals(name, product.name);     }      @Override     public int hashCode() {         return Objects.hash(name, price);     } }

在這個(gè)例子中,hashCode方法只使用了name和price屬性,因?yàn)樗鼈兪莈quals方法中用于比較的關(guān)鍵屬性。description屬性被忽略了,因?yàn)樗挥绊憣?duì)象的相等性。

不重寫(xiě)hashCode方法會(huì)怎么樣?

如果不重寫(xiě)hashCode方法,那么對(duì)象將使用默認(rèn)的hashCode方法,該方法通常是基于對(duì)象的內(nèi)存地址生成的。這意味著即使兩個(gè)對(duì)象的內(nèi)容相同,它們的hashCode值也可能不同。

這會(huì)導(dǎo)致在使用哈希表(如HashMap、HashSet)時(shí)出現(xiàn)問(wèn)題。例如,如果你將一個(gè)對(duì)象放入HashSet中,然后修改了該對(duì)象的內(nèi)容,那么HashSet可能無(wú)法找到該對(duì)象,因?yàn)樗?jì)算出的hashCode值已經(jīng)發(fā)生了改變。

更糟糕的是,如果你將兩個(gè)內(nèi)容相同的對(duì)象放入HashMap中,它們會(huì)被認(rèn)為是兩個(gè)不同的鍵,因?yàn)樗鼈兊膆ashCode值不同。這會(huì)導(dǎo)致HashMap的行為變得不可預(yù)測(cè)。

因此,如果你重寫(xiě)了equals方法,那么一定要同時(shí)重寫(xiě)hashCode方法,以保證相等的對(duì)象具有相同的hashCode值。這可以避免在使用哈希表時(shí)出現(xiàn)問(wèn)題,并且可以提高程序的性能。

什么時(shí)候可以不重寫(xiě)hashCode方法?

在極少數(shù)情況下,可以不重寫(xiě)hashCode方法:

  1. 永遠(yuǎn)不會(huì)將對(duì)象放入哈希表中: 如果你確定你的對(duì)象永遠(yuǎn)不會(huì)被用作HashMap或HashSet的鍵,那么可以不重寫(xiě)hashCode方法。但是,這通常是一個(gè)壞主意,因?yàn)槟銦o(wú)法保證將來(lái)不會(huì)改變這個(gè)決定。
  2. 對(duì)象是不可變的: 如果你的對(duì)象是不可變的,并且你沒(méi)有重寫(xiě)equals方法,那么可以不重寫(xiě)hashCode方法。因?yàn)槟J(rèn)的hashCode方法是基于對(duì)象的內(nèi)存地址生成的,而不可變對(duì)象的內(nèi)存地址在其生命周期內(nèi)不會(huì)發(fā)生改變。
  3. 性能要求極高: 在某些性能要求極高的場(chǎng)景下,可以考慮犧牲hashCode的正確性來(lái)提高性能。但是,這通常是一個(gè)非常危險(xiǎn)的做法,因?yàn)樗赡軙?huì)導(dǎo)致難以調(diào)試的錯(cuò)誤。

總的來(lái)說(shuō),重寫(xiě)hashCode方法是一個(gè)良好的編程習(xí)慣。它可以避免在使用哈希表時(shí)出現(xiàn)問(wèn)題,并且可以提高程序的性能。除非你有非常充分的理由,否則應(yīng)該始終重寫(xiě)hashCode方法。

? 版權(quán)聲明
THE END
喜歡就支持一下吧
點(diǎn)贊14 分享