1. 程式人生 > >Java hashCode的重要性

Java hashCode的重要性

在前面三篇博文中LZ講解了(HashMapHashSetHashTable),在其中LZ不斷地講解他們的put和get方法,在這兩個方法中計算key的hashCode應該是最重要也是最精華的部分,所以下面LZ揭開hashCode的“神祕”面紗。

hashCode的作用

要想了解一個方法的內在原理,我們首先需要明白它是幹什麼的,也就是這個方法的作用。在講解陣列時(java提高篇(十八)——陣列),我們提到陣列是java中效率最高的資料結構,但是“最高”是有前提的。第一我們需要知道所查詢資料的所在位置。第二:如果我們進行迭代查詢時,資料量一定要小,對於大資料量而言一般推薦集合。

在Java集合中有兩類,一類是List,一類是Set他們之間的區別就在於List集合中的元素師有序的,且可以重複,而Set集合中元素是無序不可重複的。對於List好處理,但是對於Set而言我們要如何來保證元素不重複呢?通過迭代來equals()是否相等。資料量小還可以接受,當我們的資料量大的時候效率可想而知(當然我們可以利用演算法進行優化)。比如我們向HashSet插入1000資料,難道我們真的要迭代1000次,呼叫1000次equals()方法嗎?hashCode提供瞭解決方案。怎麼實現?我們先看hashCode的原始碼(Object)。

1 public
native int hashCode();

它是一個本地方法,它的實現與本地機器有關,這裡我們暫且認為他返回的是物件儲存的物理位置(實際上不是,這裡寫是便於理解)。當我們向一個集合中新增某個元素,集合會首先呼叫hashCode方法,這樣就可以直接定位它所儲存的位置,若該處沒有其他元素,則直接儲存。若該處已經有元素存在,就呼叫equals方法來匹配這兩個元素是否相同,相同則不存,不同則雜湊到其他位置(具體情況請參考(Java提高篇()—–HashMap))。這樣處理,當我們存入大量元素時就可以大大減少呼叫equals()方法的次數,極大地提高了效率。

所以hashCode在上面扮演的角色為尋域(尋找某個物件在集合中區域位置)。hashCode可以將集合分成若干個區域,每個物件都可以計算出他們的hash碼,可以將hash碼分組,每個分組對應著某個儲存區域,根據一個物件的hash碼就可以確定該物件所儲存區域,這樣就大大減少查詢匹配元素的數量,提高了查詢效率。

hashCode對於一個物件的重要性

hashCode重要麼?不重要,對於List集合、陣列而言,他就是一個累贅,但是對於HashMap、HashSet、HashTable而言,它變得異常重要。所以在使用HashMap、HashSet、HashTable時一定要注意hashCode。對於一個物件而言,其hashCode過程就是一個簡單的Hash演算法的實現,其實現過程對你實現物件的存取過程起到非常重要的作用。

在前面LZ提到了HashMap和HashTable兩種資料結構,雖然他們存在若干個區別,但是他們的實現原理是相同的,這裡我以HashTable為例闡述hashCode對於一個物件的重要性。

一個物件勢必會存在若干個屬性,如何選擇屬性來進行雜湊考驗著一個人的設計能力。如果我們將所有屬性進行雜湊,這必定會是一個糟糕的設計,因為物件的hashCode方法無時無刻不是在被呼叫,如果太多的屬性參與雜湊,那麼需要的運算元時間將會大大增加,這將嚴重影響程式的效能。但是如果較少屬相參與雜湊,雜湊的多樣性會削弱,會產生大量的雜湊“衝突”,除了不能夠很好的利用空間外,在某種程度也會影響物件的查詢效率。其實這兩者是一個矛盾體,雜湊的多樣性會帶來效能的降低。

那麼如何對物件的hashCode進行設計,LZ也沒有經驗。從網上查到了這樣一種解決方案:設定一個快取標識來快取當前的雜湊碼,只有當參與雜湊的物件改變時才會重新計算,否則呼叫快取的hashCode,這樣就可以從很大程度上提高效能。

在HashTable計算某個物件在table[]陣列中的索引位置,其程式碼如下:

1 int index = (hash & 0x7FFFFFFF) % tab.length;

為什麼要&0x7FFFFFFF?因為某些物件的hashCode可能會為負值,與0x7FFFFFFF進行與運算可以確保index為一個正數。通過這步我可以直接定位某個物件的位置,所以從理論上來說我們是完全可以利用hashCode直接定位物件的散列表中的位置,但是為什麼會存在一個key-value的鍵值對,利用key的hashCode來存入資料而不是直接存放value呢?這就關係HashTable效能問題的最重要的問題:Hash衝突!

我們知道衝突的產生是由於不同的物件產生了相同的雜湊碼,假如我們設計物件的雜湊碼可以確保99.999999999%的不重複,但是有一種絕對且幾乎不可能遇到的衝突你是絕對避免不了的。我們知道hashcode返回的是int,它的值只可能在int範圍內。如果我們存放的資料超過了int的範圍呢?這樣就必定會產生兩個相同的index,這時在index位置處會儲存兩個物件,我們就可以利用key本身來進行判斷。所以具有相索引的物件,在該index位置處存在多個物件,我們必須依靠key的hashCode和key本身來進行區分。

hashCode與equals

在Java中hashCode的實現總是伴隨著equals,他們是緊密配合的,你要是自己設計了其中一個,就要設計另外一個。當然在多數情況下,這兩個方法是不用我們考慮的,直接使用預設方法就可以幫助我們解決很多問題。但是在有些情況,我們必須要自己動手來實現它,才能確保程式更好的運作。

對於equals,我們必須遵循如下規則:

      對稱性:如果x.equals(y)返回是“true”,那麼y.equals(x)也應該返回是“true”。

      反射性:x.equals(x)必須返回是“true”。

      類推性:如果x.equals(y)返回是“true”,而且y.equals(z)返回是“true”,那麼z.equals(x)也應該返回是“true”。

      一致性:如果x.equals(y)返回是“true”,只要x和y內容一直不變,不管你重複x.equals(y)多少次,返回都是“true”。

任何情況下,x.equals(null),永遠返回是“false”;x.equals(和x不同型別的物件)永遠返回是“false”。

對於hashCode,我們應該遵循如下規則:

      1. 在一個應用程式執行期間,如果一個物件的equals方法做比較所用到的資訊沒有被修改的話,則對該物件呼叫hashCode方法多次,它必須始終如一地返回同一個整數。

      2. 如果兩個物件根據equals(Object o)方法是相等的,則呼叫這兩個物件中任一物件的hashCode方法必須產生相同的整數結果。

      3. 如果兩個物件根據equals(Object o)方法是不相等的,則呼叫這兩個物件中任一個物件的hashCode方法,不要求產生不同的整數結果。但如果能不同,則可能提高散列表的效能。

至於兩者之間的關聯關係,我們只需要記住如下即可:

如果x.equals(y)返回“true”,那麼x和y的hashCode()必須相等。

如果x.equals(y)返回“false”,那麼x和y的hashCode()有可能相等,也有可能不等。

理清了上面的關係我們就知道他們兩者是如何配合起來工作的。先看下圖:

2014040701_thumb2

整個處理流程是:

1、判斷兩個物件的hashcode是否相等,若不等,則認為兩個物件不等,完畢,若相等,則比較equals。

2、若兩個物件的equals不等,則可以認為兩個物件不等,否則認為他們相等。

例項:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49

相關推薦

Java hashCode重要性

在前面三篇博文中LZ講解了(HashMap、HashSet、HashTable),在其中LZ不斷地講解他們的put和get方法,在這兩個方法中計算key的hashCode應該是最重要也是最精華的部分,所以下面LZ揭開hashCode的“神祕”面紗。 hashCo

java hashCode, 引用以及equals().

重復 對象 如果 contain 定義 返回 contains new java hashCode是每一個對象都有的hash碼,是HashSet中用來分配對象存儲的標識。每一個equal的對象都要有相同的hashCode。所以重寫equals方法,必重寫hashCode()

Java HashCode詳解

popu 容器類 itl 基本上 映射 nat 程序設計語言 http 容器 一、為什麽要有Hash算法 Java中的集合有兩類,一類是List,一類是Set。List內的元素是有序的,元素可以重復。Set元素無序,但元素不可重復。要想保證元素不重復,兩個元素是否重復應該依

Java HashCode

ring 字符串 integer 兩個 是否 new 內容 object 結構 在Java中,哈希碼代表了對象的一種特征,例如我們判斷某兩個字符串是否==,如果其哈希碼相等,則這兩個字符串是相等的。其次,哈希碼是一種數據結構的算法。常見的哈希碼的算法有:1:Object類的

java hashCode 作用

ring min code equals obj bool spa rri other hashCode 作用,對象根據hashCode的值分區域存放 /** * hashCode 作用 * * @author Administrator *

JAVA hashCode和equals方法詳解

hashCode和equals方法都是Object基類的方法 先看一個例子 public class Studeng { private Integer sid; private String name; public

Java hashCode的作用

1、hashCoed 的特性: (1)HashCode的存在主要是用於查詢的快捷性,如Hashtable,HashMap等,HashCode經常用於確定物件的儲存地址; (2)如果兩個物件相同, equals方法一定返回true,並且這兩個物件的HashCode一定相同;

Java Hashcode

empty 產生 地方 重要 pack res sta ring 數據結構 哈希值這個應該都聽過,並且用於hashMap, hashSet, HashTable.後面對這三個進行詳細說明。 哈希表這個數據結構想必大多數人都不陌生,而且在很多地方都會利用到hash表來提高查找

Java hashCode()和equals()的若干問題解答

本章的內容主要解決下面幾個問題: 1.equals()的作用是什麼? 2.equals()與==的區別是什麼? 3.hashCode()的作用是什麼? 4.hashCode()和equals()之間有什麼聯絡? 第一部分 equals()的作用 equals()的作

[ 轉]Java hashCode() 和 equals()的若干問題解答

1 import java.util.*; 2 import java.lang.Comparable; 3 4 /** 5 * @desc 比較equals() 返回true 以及 返回false時, hashCode()的值。 6 * 7 * @author skywang 8

Java hashcode與collection 的關係

collection 類物件在呼叫remove,contains 等方法時需要比較對像是否相等,會涉及到hashcode,和equals.()方法 內容相等的兩個對像其hashcode 值是相等的 equals()相等=》hashcode 相等反之不成立

JAVA hashcode和equals為何要同時重寫

hashCode是雜湊碼,用來快速查詢用的 你看到的那一串的格式如下,比如一個[email protected] "@ "前面的是你的類名,後面的就是雜湊碼的16進製表示。hashCode的

java核心技術-Object hashCode

object hashcode java核心技術 hashCode(散列碼)是由對象導出的一個整型值,散列碼是沒有規律的,如果對象不一樣,其散列碼基本也不會一致。 (String)字符串的散列碼是有內容導出的,兩個相同內容的String,其散列碼是一致的,但是StringBuff

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

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

淺談Java中的hashCode方法

implement state ask get() 存在 rsa key 沖突 如何 哈希表這個數據結構想必大多數人都不陌生,而且在很多地方都會利用到hash表來提高查找效率。在Java的Object類中有一個方法: public native int hashCode(

Java == ,equals 和 hashcode 的區別和聯系

應對 哈希表 返回對象 com 總結 子類 return 地址 內存 1. == java中的==是比較兩個對象在JVM中的地址。比較好理解。看下面的代碼: public class ComAddr{ public static void main(St

Java中的equals()和hashCode()

sea 接口 後來 ide itl 一個數 毫無 exceptio title 概述 在我們使用類集框架(比方使用hashMap、hashSet)的時候,常常會涉及到重寫equals()和hashCode()這兩個方法。 這兩個方法的聯系是:

閱讀源代碼的重要性:如廚師選食材,耍廚具——在Eclipse中怎樣查看Java、Android源代碼

系統 spa san text progress 啟動 找到 排序 javap 首先,非常多人說,不會看jdk中的源代碼就不叫學過Java。顯然這是肯定的。打個例如:真正的廚師須要從食材的選取、加工。到最後的烹飪、裝盤成型,甚至到最後給用戶介紹食用方法等一整套流程走

Java:驗證在類繼承過程中equals()、 hashcode()、toString()方法的使用

red ger 輸出 ria oid nag println manage base 以下通過實際例子對類創建過程匯中常用的equals()、hashcode()、toString()方法進行展示,三個方法的創建過程具有通用性,在項目中可直接改寫。 //通過超類Employ

java :equals()和hashcode()方法的結合使用

pro 解決 java lin testin ren use main 結合 哈希表這個數據結構想必大多數人都不陌生,而且在很多地方都會利用到hash表來提高查找效率。在Java的Object類中有一個方法: 1 public native int hashCo