HashCode的作用原理和實例解析


1.  HashCode的特性

(1)HashCode的存在主要是用於快速查找,如GC查找要回收的對象,Hashtable,HashMap等,HashCode經常用於確定對象的存儲地址;

(2)如果兩個對象相同,hashcode一定相同,並且equals方法一定返回true;

(3)兩個對象的HashCode相同,並不一定表示兩個對象就相同,即equals()不一定為true,只能說明這兩個對象在一個散列存儲結構中。

(4)如果對象的equals方法被重寫,那么對象的HashCode也盡量重寫。

本文原創,轉載請注明出處:http://blog.csdn.net/seu_calvin/article/details/52094115

 

2.  HashCode作用

Java中的集合有兩類,一類是List,再有一類是Set。前者集合內的元素是有序的,元素可以重復;后者元素無序,但元素不可重復。 equals方法可用於保證元素不重復,但如果每增加一個元素就檢查一次,若集合中現在已經有1000個元素,那么第1001個元素加入集合時,就要調用1000次equals方法。這顯然會大大降低效率。 於是,Java采用了哈希表的原理。

 哈希算法也稱為散列算法,是將數據依特定算法直接指定到一個地址上。這樣一來,當集合要添加新的元素時,先調用這個元素的HashCode方法,就一下子能定位到它應該放置的物理位置上。

(1)如果這個位置上沒有元素,它就可以直接存儲在這個位置上,不用再進行任何比較了;

(2)如果這個位置上已經有元素了,就調用它的equals方法與新元素進行比較,相同的話就不存了;

(3)不相同的話,也就是發生了Hash key相同導致沖突的情況,那么就在這個Hash key的地方產生一個鏈表,將所有產生相同HashCode的對象放到這個單鏈表上去,串在一起。這樣一來實際調用equals方法的次數就大大降低了,幾乎只需要一兩次。 

 

如何理解HashCode的作用:

從Object角度看,JVM每new一個Object,它都會將這個Object丟到一個Hash表中去,這樣的話,下次做Object的比較或者取這個對象的時候(讀取過程),它會根據對象的HashCode再從Hash表中取這個對象。這樣做的目的是提高取對象的效率。若HashCode相同再去調用equal。
 

3.  HashCode實踐

 HashCode是用於查找使用的,而equals是用於比較兩個對象是否相等的。

(1)例如內存中有這樣的位置 :

0 1 2 3 4 5 6 7
而我有個類,這個類有個字段叫ID,我要把這個類存放在以上8個位置之一,如果不用HashCode而任意存放,那么當查找時就需要到這八個位置里挨個去找,或者用二分法一類的算法。  但以上問題如果用HashCode就會使效率提高很多。  定義我們的HashCode為ID%8,比如我們的ID為9,9除8的余數為1,那么我們就把該類存在1這個位置,如果ID是13,求得的余數是5,那么我們就把該類放在5這個位置。依此類推。  

(2)如果兩個類有相同的HashCode,例如9除以8和17除以8的余數都是1,也就是說,我們先通過 HashCode來判斷兩個類是否存放某個桶里,但這個桶里可能有很多類,那么我們就需要再通過equals在這個桶里找到我們要的類。  

 

請看下面這個例子 :

public class HashTest {
private int i;

public int getI() {
return i;
}

public void setI(int i) {
this.i = i;
}

public int hashCode() {
return i % 10;
}

public final static void main(String[] args) {
HashTest a = new HashTest();
HashTest b = new HashTest();
a.setI(1);
b.setI(1);
Set<HashTest> set = new HashSet<HashTest>();
set.add(a);
set.add(b);
System.out.println(a.hashCode() == b.hashCode());
System.out.println(a.equals(b));
System.out.println(set);
}
}
輸出結果為:

​true
false
[HashTest@1, HashTest@1]
以上這個示例,我們只是重寫了HashCode方法,從上面的結果可以看出,雖然兩個對象的HashCode相等,但是實際上兩個對象並不是相等,因為我們沒有重寫equals方法,那么就會調用Object默認的equals方法,顯示這是兩個不同的對象。

這里我們將生成的對象放到了HashSet中,而HashSet中只能夠存放唯一的對象,也就是相同的(適用於equals方法)的對象只會存放一個,但是這里實際上是兩個對象ab都被放到了HashSet中,這樣HashSet就失去了他本身的意義了。

下面我們繼續重寫equals方法:

public class HashTest {
private int i;

public int getI() {
return i;
}

public void setI(int i) {
this.i = i;
}

public boolean equals(Object object) {
if (object == null) {
return false;
}
if (object == this) {
return true;
}
if (!(object instanceof HashTest)) {
return false;
}
HashTest other = (HashTest) object;
if (other.getI() == this.getI()) {
return true;
}
return false;
}

public int hashCode() {
return i % 10;
}

public final static void main(String[] args) {
HashTest a = new HashTest();
HashTest b = new HashTest();
a.setI(1);
b.setI(1);
Set<HashTest> set = new HashSet<HashTest>();
set.add(a);
set.add(b);
System.out.println(a.hashCode() == b.hashCode());
System.out.println(a.equals(b));
System.out.println(set);
}
}
輸出結果如下所示。

從結果我們可以看出,現在兩個對象就完全相等了,HashSet中也只存放了一份對象。

true
true
[HashTest@1]


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM