內存泄漏避雷!你真的瞭解重寫equals()和hashcode()方法的緣由嗎?| 8月更文挑戰

基本概念

  • 要比較兩個對象是否相等時須要調用對象的equals() 方法:
    • 判斷對象引用所指向的對象地址是否相等
  • 對象地址相等時, 那麼對象相關的數據也相等,包括:
    • 對象句柄
    • 對象頭
    • 對象實例數據
    • 對象類型數據
  • 能夠經過比較對象的地址來判斷對象是否相等

Object源碼

  • 對象在不重寫的狀況下使用的是Object中的equals() 方法和hashCode() 方法
    • equals(): 判斷的是兩個對象的引用是否指向同一個對象
    • hashCode(): 根據對象地址生成一個整數數值
  • ObjecthashCode() 方法修飾符爲native: 代表該方法是由操做系統實現. Java調用操做系統底層代碼獲取Hash
public native int hashCode();
複製代碼

重寫equals

  • 重寫equals()方法的場景:
    • 假設如今有不少學生對象
    • 默認狀況下,要判斷多個學生對象是否相等,須要根據地址判斷:
      • 若對象地址相等,那麼對象實例的數據必定是同樣的
    • 判斷相等的要求:
      • 當學生的姓名,年齡,性別相等時,認爲對象是相等的,
      • 不必定須要對象的地址徹底相同
  • 重寫了equals() 方法後,這裏會輸出 [s1==s2]
  • 若是沒有重寫 equals() 方法,那麼一定會輸出 [s1!=s2]

重寫hashCode

  • 根據重寫equals的方法,上述s1和s2認爲是相等的java

  • Object中的hashCode()方法:算法

    • equals() 方法沒被修改的前提下,屢次調用同一個對象的hashCode() 方法返回的值必須是相同的正數
    • 若是兩個對象互相equals(), 那麼這兩個對象的hashcode值必須相等
    • 爲不一樣的對象生成不一樣的hashcode能夠提高Hash表的性能
  • HashSet底層實現:數組

    • HashSet底層是經過HashMap實現的
    • 比較Set容器內元素是否相等是經過比較對象的hashcode來判斷是否相等的
  • hashCode()的寫法:markdown

    • 首先整理出判斷對象相等的屬性
    • 而後去一個儘量小的正整數,防止最終結果超出整型int的取數範圍
    • 而後計算[正整數 * 屬性的hashCode + 其他某個屬性的hashCode]
    • 重複步驟

原理分析

  • 由於沒有重寫父類的ObjecthashCode() 方法,因此ObjecthashCode() 方法會根據兩個對象的地址生成響應的hashcode
  • 因爲兩個對象分別是實體類建立的不一樣的實例,因此地址確定是不同的,那麼hashcode值也是不同的
  • Set區別對象是否是惟一的標準:
    • 兩個對象的hashcode值是否同樣
    • 而後再斷定兩個對象是否equals
  • Map區別對象是否是惟一的標準:
    • 先根據Key值的hashcode分配來獲取保存數組下標
    • 而後再根據eaquals區分是不是惟一值

HashMap

HashMap組成結構

  • HashMap: 是由數組鏈表組成的

HashMap的存儲

  • HashMap的存儲:
    • 一個對象存儲到HashMap中的位置是由keyhashcode值決定的
    • HashMap查找key:
      • 查找key,hashMap會先根據key值的hashcode通過取餘算法定位所在數組的位置
      • 而後根據keyequals方法匹配相同的key值獲取相應的對象
  • 存值規則:
    • KeyhashcodeHashMap的容量,進行取餘運算得出該Key存儲在數組所在位置的下標
  • HashMap查找key:
    • 獲得key在數組中的位置
    • 匹配獲得對應key值對象
    • 而後將上述多個對象根據key.equals() 來匹配獲取對應的key的數據對象
  • HashMap中的hashCode:
    • 若是沒有hashcode就意味着HashMap存儲的時候是沒有規律可循的
    • 這樣每次使用map.get() 方法,就要將map裏的對象一一進行equals匹配,致使效率低下
相關文章
相關標籤/搜索