1. 程式人生 > >為什麼要重寫了equals方法後一定要重寫hashcode方法

為什麼要重寫了equals方法後一定要重寫hashcode方法

重寫了equals方法一定要重寫hashcode方法,原因在於用到hash來提高效率的集合類在插入物件時先比較物件的hashcode是否相同,若相同再比較equals是否相同,若hashcode不同j就不再比較equals。

雜湊表這個資料結構想必大多數人都不陌生,而且在很多地方都會利用到hash表來提高查詢效率。在Java的Object類中有一個方法:

1 public native int hashCode();
根據這個方法的宣告可知,該方法返回一個int型別的數值,並且是本地方法,因此在Object類中並沒有給出具體的實現。

為何Object類需要這樣一個方法?它有什麼作用呢?今天我們就來具體探討一下hashCode方法。


一、hashcdoe方法的作用

對於包含容器型別的程式設計語言來說,基本上都會涉及到hashCode。在Java中也一樣,hashCode方法的主要作用是為了配合基於雜湊的集合一起正常執行,這樣的雜湊集合包括HashSet、HashMap以及HashTable。

為什麼這麼說呢?考慮一種情況,當向集合中插入物件時,如何判別在集合中是否已經存在該物件了?(注意:集合中不允許重複的元素存在)

也許大多數人都會想到呼叫equals方法來逐個進行比較,這個方法確實可行。但是如果集合中已經存在一萬條資料或者更多的資料,如果採用equals方法去逐一比較,效率必然是一個問題。

此時hashCode方法的作用就體現出來了,當集合要新增新的物件時,先呼叫這個物件的hashCode方法,得到對應的hashcode值,實際上在HashMap的具體實現中會用一個table儲存已經存進去的物件的hashcode值,如果table中沒有該hashcode值,它就可以直接存進去,不用再進行任何比較了;如果存在該hashcode值, 就呼叫它的equals方法與新元素進行比較,相同的話就不存了,不相同就雜湊其它的地址,所以這裡存在一個衝突解決的問題,這樣一來實際呼叫equals方法的次數就大大降低了,說通俗一點:Java中的hashCode方法就是根據一定的規則將與物件相關的資訊(比如物件的儲存地址,物件的欄位等)對映成一個數值,這個數值稱作為雜湊值。


下面這段程式碼是java.util.HashMap的中put方法的具體實現:

public V put(K key, V value) { if (key == null) return putForNullKey(value); int hash = hash(key.hashCode()); int i = indexFor(hash, table.length); for (Entry<K,V> e = table[i]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } modCount++; addEntry(hash, key, value, i); return null; } put方法是用來向HashMap中新增新的元素,從put方法的具體實現可知,會先呼叫hashCode方法得到該元素的hashCode值,然後檢視table中是否存在該hashCode值,如果存在則呼叫equals方法重新確定是否存在該元素,如果存在,則更新value值,否則將新的元素新增到HashMap中。從這裡可以看出,hashCode方法的存在是為了減少equals方法的呼叫次數,從而提高程式效率。

因此有人會說,可以直接根據hashcode值判斷兩個物件是否相等嗎?肯定是不可以的,因為不同的物件可能會生成相同的hashcode值。雖然不能根據hashcode值判斷兩個物件是否相等,但是可以直接根據hashcode值判斷兩個物件不等,如果兩個物件的hashcode值不等,則必定是兩個不同的物件。如果要判斷兩個物件是否真正相等,必須通過equals方法。

也就是說對於兩個物件,如果呼叫equals方法得到的結果為true,則兩個物件的hashcode值必定相等;

如果equals方法得到的結果為false,則兩個物件的hashcode值不一定不同;

如果兩個物件的hashcode值不等,則equals方法得到的結果必定為false;

如果兩個物件的hashcode值相等,則equals方法得到的結果未知。


相關推薦

為什麼重寫equals方法一定重寫hashcode方法

重寫了equals方法一定要重寫hashcode方法,原因在於用到hash來提高效率的集合類在插入物件時先比較物件的hashcode是否相同,若相同再比較equals是否相同,若hashcode不同j就不再比較equals。 雜湊表這個資料結構想必大多數人都不陌生,而且

為什麼重寫equals方法一定重寫HashCode方法?(

使用HashMap,如果key是自定義的類,就必須重寫hashcode()和equals()。     1.hashcode()和equals()是在哪裡被用到的?什麼用的?      HashMap是基於雜湊函式,以陣列和連結串列的方式實現的。  而對於每一個物件,通過其hashCode()方法可為其生成一

Java--什麼時候需要重寫equals方法?為什麼重寫equals方法一定重寫HashCode方法

何時需要重寫equals() 當一個類有自己特有的“邏輯相等”概念(不同於物件身份的概念)。 設計equals() [1]使用instanceof操作符檢查“實參是否為正確的型別”。 [2]對於類中的每一個“關鍵域”,檢查實參中

【Java基礎之重寫equalshashCode和compareTo方法】什麼時候需要重寫重寫equals方法?為什麼重寫equals方法一定重寫HashCode方法

1.何時需要重寫equals() 當一個類有自己特有的“邏輯相等”概念(不同於物件身份的概念)。 2.設計equals() [1]使用instanceof操作符檢查“實參是否為正確的型別”。 [2]對於類中的每一個“關鍵域”,檢查實參中的域與當前物件中對應的域值。 [2

respondsToSelector的相關使用(非常好用的方法一定解!!!)

-(BOOL) isKindOfClass: classObj 用來判斷是否是某個類或其子類的例項 -(BOOL) isMemberOfClass: classObj 用來判斷是否是某個類的例項 -(BOOL) respondsToSelector: selector

Laravel修改配置一定清理緩存 "php artisan config:clear"!

copy 折騰 In IV 使用 plain ear 1.5 net 用laravel踩到一個大坑。。。 需要使用laravel的隊列(queue)功能, 設置 ".env"配置文件 QUEUE_DRIVER=database 按照文檔,建立jobs數據表,生成任務類,

為什麼在重寫equals()方法之後也必須重寫hashCode()方法

我們都知道Java語言是完全面向物件的,在java中,所有的物件都是繼承於Object類。Ojbect類中有兩個方法equals、hashCode,這兩個方法都是用來比較兩個物件是否相等的。         對於值物件,==比較的是兩個物件的值,對於引用物件,比較的是兩

區域性變數Executors建立執行緒池一定關閉

參考: http://curious.iteye.com/blog/2298849 網上有很多Executors的例子,但有些寫的非常草率,都只是寫如何建立,但有些沒有附上關閉方法。 Executors作為區域性變數時,建立了執行緒,一定要記得呼叫executor

xampp配置虛擬域名之後一定加上埠號????

答案是這樣的: 1.瀏覽網頁服務預設的埠號都是80,因此只需輸入網址即可,不用輸入“:80”,意思是 80 埠可預設。 2.注意:預設只是你不寫,瀏覽器還是要替你加上的 。 3.而xampp很多時候因為軟體佔用埠號產生衝突的原因,我們需要去更改apac

NSTimer計時器的使用,建立一定銷燬,不然會重複使用

計時器的使用,建立後一定要銷燬,不然會重複使用 #pragma mark - 判斷活動是否開始-倒計時 - (void)judementActiveTime {        if (!_activeTimer)        {            //

耗時方法一定做執行緒檢查

前言 主執行緒又稱UI執行緒,是不能做耗時任務的,否則會導致UI介面卡頓甚至ANR。 最常見的case就是如果我們在主執行緒做訪問網路操作會丟擲NetworkOnMainThreadException

String重寫equals方法,StringBuffer沒有重寫equals方法

System.out.println(new String("abc").equals(new String("abc")));//true System.out.println(new StringBuffer("abc").equals(new StringBuffer

Django(博客系統):重寫auth.User使用createsupperuser出錯解決辦法

run app back logs turn ida utili command ron 背景:重寫django的系統User後,使用createsupperuser創建用戶失敗 由於項目需要擴展django默認新的auth.User系統(添加兩個字段:頭像、簡介等字段)

人不一定生得漂亮,但一定活得漂亮!

ORA-00001: 違反唯一約束條件 (.) ORA-00017: 請求會話以設定跟蹤事件 ORA-00018: 超出最大會話數 ORA-00019: 超出最大會話許可數 ORA-00020: 超出最大程序數 () ORA-00021: 會話附屬於其它某些程序;無法轉換會話

關於Android中呼叫post方法貌似沒有執行run方法的解釋及解決辦法

(真糾結,剛剛發了之後才發現排版太亂了,稍作修改再發了哈~) 哎……之前糾結過Handler的執行機制,後來貌似懂了,但是近幾天又被自己的工程繞的好像又不懂了一樣!! 其實之前理解還是對的哈~只是這次的工程裡的各個變數和物件的定義和初始化位置不適當才造成表面上貌似

覆蓋(不是過載)equals方法,請一定覆蓋hashCode方法

為了能讓集合框架中的類如HashMap正常工作,必須保證同時覆蓋equals()和hashCode(),而且注意不要由於寫錯了引數型別,而過載了這兩個方法,卻並沒有覆蓋它們,比如:  public boolean equals(Object obj) 寫成了public boolean equals(Cla

9. 【對於所有物件都通用的方法重寫equals方法一定重寫hashCode方法

本文是《Effective Java》讀書筆記第9條,其中內容可能會結合實際應用情況或參考其他資料進行補充或調整。 在每個覆蓋了equals方法的類中,一定也要覆蓋hasCode方法。否則會導致該類無法結合所有基於雜湊的集合(比如HashMap、HashS

JAVA中重寫equals()方法的同時重寫hashcode()方法

內存地址 his mov bool args 變量 維護 log obj object對象中的 public boolean equals(Object obj),對於任何非空引用值 x 和 y,當且僅當 x 和 y 引用同一個對象時,此方法才返回 true;註意:當此方法

【java基礎】重寫equals()方法的同時重寫hashCode()方法

而且 通過 才會 默認 什麽 需要 現在 ash 字段 1、 為什麽要重寫equals方法? 因為Object的equal方法默認是兩個對象的引用的比較,意思就是指向同一內存,地址則相等,否則不相等;如果你現在需要利用對象裏面字段的值來判斷是否相等,則重寫equals方法。