hashCode() 的做用是獲取哈希碼,也稱爲散列碼;它其實是返回一個int整數。這個散列碼的做用是肯定該對象在散列表中的索引位置,若是有看個人上一篇文章 什麼是散列表,那麼這裏的散列碼就至關於上文中根據首字母查詢散列表例子中 人名關鍵字k在散列表中的具體地址。hashCode() 定義在JDK的Object.java中,這就意味着Java中的任何類都包含有hashCode() 函數。java
數組是java中效率最高的數據結構,可是「最高」是有前提的。第一咱們須要知道所查詢數據的所在位置。第二:若是咱們進行迭代查找時,數據量必定要小,對於大數據量而言通常推薦集合。算法
在 Java 集合中有兩類,一類是 List,一類是 Set 他們之間的區別就在於 List 集合中的元素師有序的,且能夠重複,而 Set 集合中元素是無序不可重複的。對於 List 好處理,可是對於 Set 而言咱們要如何來保證元素不重複呢?經過迭代來 equals() 是否相等。數據量小還能夠接受,當咱們的數據量大的時候效率可想而知(固然咱們能夠利用算法進行優化)。好比咱們向 HashSet 插入 1000 數據,難道咱們真的要迭代 1000 次,調用 1000 次 equals() 方法嗎?hashCode 提供瞭解決方案。怎麼實現?咱們先看 hashCode 的源碼(Object)。segmentfault
public native int hashCode();
它是一個本地方法,它的實現與本地機器有關。當咱們向一個集合中添加某個元素,集合會首先調用 hashCode 方法,這樣就能夠直接定位它所存儲的位置,若該處沒有其餘元素,則直接保存。若該處已經有元素存在,就調用 equals 方法來匹配這兩個元素是否相同,相同則不存,不一樣則散列到其餘位置。這樣處理,當咱們存入大量元素時就能夠大大減小調用 equals() 方法的次數,極大地提升了效率。數組
因此 hashCode 在上面扮演的角色爲尋域(尋找某個對象在集合中區域位置)。hashCode 能夠將集合分紅若干個區域,每一個對象均可以計算出他們的 散列碼,能夠將 散列碼分組,每一個分組對應着某個存儲區域(散列表),根據一個對象的 散列碼就能夠肯定該對象所存儲區域,這樣就大大減小查詢匹配元素的數量,提升了查詢效率。緩存
hashCode 重要麼?不重要,對於 List 集合、數組而言,可是對於 HashMap、HashSet、HashTable 而言,它變得異常重要。因此在使用 HashMap、HashSet、HashTable 時必定要注意 hashCode。對於一個對象而言,其 hashCode 過程就是一個簡單的 Hash 算法的實現,其實現過程對你實現對象的存取過程起到很是重要的做用。數據結構
以 HashTable 爲例闡述 hashCode 對於一個對象的重要性。函數
一個對象勢必會存在若干個屬性,如何選擇屬性來進行散列考驗着一我的的設計能力。若是咱們將全部屬性進行散列,這一定會是一個糟糕的設計,由於對象的 hashCode 方法無時無刻不是在被調用,若是太多的屬性參與散列,那麼須要的操做數時間將會大大增長,這將嚴重影響程序的性能。可是若是較少屬相參與散列,散列的多樣性會削弱,會產生大量的散列「衝突」,除了不可以很好的利用空間外,在某種程度也會影響對象的查詢效率。其實這二者是一個矛盾體,散列的多樣性會帶來性能的下降。性能
那麼如何對對象的 hashCode 進行設計,本人 也沒有經驗。從網上查到了這樣一種解決方案:設置一個緩存標識來緩存當前的散列碼,只有當參與散列的對象改變時纔會從新計算,不然調用緩存的 hashCode,這樣就能夠從很大程度上提升性能。大數據
在 HashTable 計算某個對象在 table[] 數組中的索引位置,其代碼以下:優化
int index = (hash & 0x7FFFFFFF) % tab.length;
爲何要 &0x7FFFFFFF?由於某些對象的 hashCode 可能會爲負值,與 0x7FFFFFFF 進行與運算能夠確保 index 爲一個正數。經過這步我能夠直接定位某個對象的位置,因此從理論上來講咱們是徹底能夠利用 hashCode 直接定位對象的散列表中的位置,可是爲何會存在一個 key-value 的鍵值對,利用 key 的 hashCode 來存入數據而不是直接存放 value 呢?這就關係 HashTable 性能問題的最重要的問題: Hash 衝突!(詳見上篇)
咱們知道衝突的產生是因爲不一樣的對象產生了相同的散列碼, hashcode 返回的是 int,它的值只可能在 int 範圍內。若是咱們存放的數據超過了 int 的範圍呢?這樣就一定會產生兩個相同的 散列碼,這時在 散列碼 位置處會存儲兩個對象,咱們就能夠利用 key 自己來進行判斷。因此具備相索引的對象,在該 散列碼 位置處存在多個對象,咱們必須依靠 key 的 hashCode 和key 自己來進行區分。而Key的比較就用到了equals
簡而言之就是:
對象的比較過程以下: