JAVA學習之HashCode,javahashcode
public native int hashCode();
返回該對象的雜湊碼值。支援此方法是為了提高雜湊表(例如 java.util.Hashtable 提供的雜湊表)的效能。
一、HashCode的作用
我們通常會用equals判斷集合中是否包含一個對象,這種方式需要遍曆集合中每一個元素,然後對他們一一進行equals方法比較。對於少量資料的集合該方式自然可以,但當我們的資料很多例如一萬個,如果還使用這種逐個遍曆的方式顯然不合適。於是有人發明了一種雜湊演算法來提高從集合中尋找元素的效率。這種方式的核心就是將集合分為若干個地區,每個對象可以計算出一個雜湊碼,可以將雜湊碼分組,每組分別對應某個儲存地區,尋找對象時我們先根據對象的雜湊碼來確定該Object Storage Service在某個地區。然後在這個地區內尋找元素。
在java中HashSet、HashMap以及HashTable這些散列集合,就是與hashCode方法一起使用。
下面這段代碼是java.util.HashMap的中put方法的具體實現:
public V put(K key, V value) { if (table == EMPTY_TABLE) { inflateTable(threshold); } if (key == null) return putForNullKey(value); int hash = hash(key); 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方法的調用次數,從而提高程式效率。
二、equals與HashCode
1、equals與HashCode必須一起出現
在put()方法中為什麼判斷HashCode後還要判斷equals?
因為不同的對象可能會產生相同的hashcode值,所以我們不能根據hashcode值判斷兩個對象是否相等。但是可以直接根據hashcode值判斷兩個對象不等,如果兩個對象的hashcode值不等,則必定是兩個不同的對象。如果要判斷兩個對象是否真正相等,必須通過equals方法。
所以我們在重寫equals方法時一定要重寫hashcode方法。因為散列集合在添加資料的時候會先判斷對象的hashCode值,hashcode值不同,他們就會被散列在不同的儲存地區,所以接下來再比較equals的時候已經沒有意義了,這個時候就違背了集合的意義(不允許重複元素的 集合)。
2、保證集合中的對象的hashcode值不能改變
當一個對象被儲存在散列集合後,就不能修改這個對象中的哪些參與計算雜湊值的欄位了,否則,對象修改後的雜湊值與最初存入集合時的雜湊值不相等了,在這中情況中,及時在contains方法使用該對象的當前應用作為參數去散列集合中檢索對象,也將出現找不到對象的結果,這將會導致無法從散列集合中單獨刪除當前對象,從而照成記憶體溢出。
使用HashSet示範:
package com.jalja.org.base.test;import java.util.HashSet;import java.util.Set;public class Point { private int x; private int y; public Point(int x, int y) { super(); this.x = x; this.y = y; } public int getX() { return x; } public void setX(int x) { this.x = x; } public int getY() { return y; } public void setY(int y) { this.y = y; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + x; result = prime * result + y; return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Point other = (Point) obj; if (x != other.x) return false; if (y != other.y) return false; return true; } public static void main(String[] args) { Point point1=new Point(1,2); Point point2=new Point(2,3); Point point3=new Point(3,4); Set<Point> set=new HashSet<Point>(); set.add(point1); set.add(point2); set.add(point3); System.out.println(set.size());//3 point1.setX(5);//改變 point1的x值 set.remove(point1);//移除 point1 System.out.println(set.size());//3 }}
從結果可以看出 point1已經無法刪除了。