HashCode的做用(以java爲例)

關於Hashcode的做用 
  總的來講,Java中的集合(Collection)有兩類,一類是List,再有一類是Set。前者集合內的元素是有序的,元素能夠重複;後者元素無序,但元素不可重複。 
       要想保證元素不重複,可兩個元素是否重複應該依據什麼來判斷呢?這就是Object.equals方法了。可是,若是每增長一個元素就檢查一 次,那麼當元素不少時,後添加到集合中的元素比較的次數就很是多了。也就是說,若是集合中如今已經有1000個元素,那麼第1001個元素加入集合時,它 就要調用1000次equals方法。這顯然會大大下降效率。 
       因而,Java採用了哈希表的原理。哈希算法也稱爲散列算法,是將數據依特定算法直接指定到一個地址上。這樣一來,當集合要添加新的元素時,先調用這個元素的hashCode方法,就一會兒能定位到它應該放置的物理位置上。若是這個位置上沒有元素,它就能夠 直接存儲在這個位置上,不用再進行任何比較了;若是這個位置上已經有元素了,就調用它的equals方法與新元素進行比較,相同的話就不存了;不相同,也就是發生了Hash key相同致使衝突的狀況,那麼就在這個Hash key的地方產生一個鏈表,將全部產生相同hashcode的對象放到這個單鏈表上去,串在一塊兒。因此這裏存在一個衝突解決的問題(不多出現)。這樣一來實際調用equals方法的次數就大大下降了,幾乎只須要一兩次。 
       因此,Java對於eqauls方法和hashCode方法是這樣規定的: 
           一、若是兩個對象相等,那麼它們的hashCode值必定要相等; 
           二、若是兩個對象的hashCode相等,它們並不必定相等。 
上面說的對象相等指的是用eqauls方法比較。 

============================================================ 
如何理解hashCode的做用: 
============================================================ 
以java.lang.Object來理解,JVM每new一個Object,它都會將這個Object丟到一個Hash哈希表中去,這樣的話,下次作Object的比較或者取這個對象的時候,它會根據對象的hashcode再從Hash表中取這個對象。這樣作的目的是提升取對象的效率。具體過程是這樣: 
1.new Object(),JVM根據這個對象的Hashcode值,放入到對應的Hash表對應的Key上,若是不一樣的對象確產生了相同的hash值,也就是發生了Hash key相同致使衝突的狀況,那麼就在這個Hash key的地方產生一個鏈表,將全部產生相同hashcode的對象放到這個單鏈表上去,串在一塊兒。 
2.比較兩個對象的時候,首先根據他們的hashcode去hash表中找他的對象,當兩個對象的hashcode相同,那麼就是說他們這兩個對象放在Hash表中的同一個key上,那麼他們必定在這個key上的鏈表上。那麼此時就只能根據Object的equal方法來比較這個對象是否equal。當兩個對象的hashcode不一樣的話,確定他們不能equal. 

============================================================   
改寫equals時老是要改寫hashCode 
============================================================ 
java.lang.Object中對hashCode的約定: 

   1. 在一個應用程序執行期間,若是一個對象的equals方法作比較所用到的信息沒有被修改的話,則對該對象調用hashCode方法屢次,它必須始終如一地返回同一個整數。 
   2. 若是兩個對象根據equals(Object o)方法是相等的,則調用這兩個對象中任一對象的hashCode方法必須產生相同的整數結果。 
   3. 若是兩個對象根據equals(Object o)方法是不相等的,則調用這兩個對象中任一個對象的hashCode方法,不要求產生不一樣的整數結果。但若是能不一樣,則可能提升散列表的性能。  java

(如下的測試代碼,我稍微修改過) 算法

import java.util.*;
public class AboutHashCode {

	public static void main(String[] args) {
		HashSet stringSet = new HashSet<V>();
		for(int i=0; i<10; i++)
		stringSet.add(new String("test"));//默認重寫equals().hashcode()
									//產生相同的hashcode,並且equals返回true因此不加進去;
		System.out.println(stringSet.size());

		
		HashSet vSet = new HashSet<V>();
		for (int i = 0; i < 10; i++) {
			vSet.add(new V(i/2));
		}
		System.out.println(vSet.size());
	}

	public static class V {
	int i;
	public V(int i) {
		this.i = i;
	}
	public int getI() {
		return this.i;
	}
	public boolean equals(Object o) {
		V v = (V) o;
		System.out.print("hashcode相同的,而後才執行的equals()方法的!");
		System.out.println(v.getI() == this.i);
		return v.getI() == this.i;
	}
	//若是不重寫,將會產生不一樣的hashcode,因此能夠加進set裏面
	public int hashCode() {
		System.out.println("先執行hashCode()方法的!");
		return i;
	}
}
	
}
相關文章
相關標籤/搜索