實體類:
package com.itcast.day1;public class ReflectPoint { PRivate int x; public int y; public ReflectPoint(int x, int y) { super(); this.x = x; 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; ReflectPoint other = (ReflectPoint) obj; if (x != other.x) return false; if (y != other.y) return false; return true; } }
測試類:
package com.itcast.day1;import java.util.Collection;import java.util.HashSet;public class ReflectTest2 { public static void main(String[] args) {// Collection collections = new ArrayList(); Collection collections = new HashSet(); ReflectPoint pt1=new ReflectPoint(3,3); ReflectPoint pt2=new ReflectPoint(5,5); ReflectPoint pt3=new ReflectPoint(3,3); //ReflectPoint類重寫了hashCode方法---算法依據x,y。 collections.add(pt1);//放入 collections.add(pt2);//放入 collections.add(pt3);//hashCode比較后,和pt1在同一區域;比較equals發現相同,舍棄pt3這個引用 collections.add(pt1);//hashCode比較后,和pt1在同一區域;比較equals發現相同,舍棄 System.out.println("修改pt2.y 前, size= "+collections.size());//2 最終放入collections 了2個元素 pt2.y=4;//修改參與進行hashCode運算的 y值,則pt2此時的hashCode和上面放入collections時的hashCode是不相等的。 //這將導致Java系統無法在collections中檢索到。 collections.remove(pt2);//檢索不到這個修改后的pt2存儲區域,自然就刪掉pt2失敗 System.out.println("修改pt2.y 后, size= "+collections.size());//2 所以 System.out.println("BB".hashCode()=="Aa".hashCode());//true 即:equals不相等,hashCode相等 } /** * 在hash集合中,放入元素前,會先計算元素的hashCode, * 然后根據這個hashCode來決定存放在哪個區域。 * * 如果想查找一個集合中是否包含有某個對象,大概的程序代碼怎么寫呢?你通常是 *逐一去除每個元素與要查找的對象進行比較,當發現某個元素要與查找的對象進行equals *方法比較的結果相等時,則停止繼續查找并返回肯定的信息,否則,返回否定的信息。 *如果一個集合中有很多個元素,譬如有一萬個元素,并且沒有包含要查找的對象時, *則意味著你的程序需要從該集合中取出一萬個元素進行逐一的比較才能得出結論。 * 有人發明了一種哈希算法來提高沖擊和中查找元素的效率,這種方式將集合分為若干 *個存儲區域,每個對象可以計算出一個哈希碼,可以將哈希碼分組,每組分別對應某個存儲 *區域,每個對象可以計算出一個哈希碼,可以將哈希碼分組,每組分別對應某個存儲區域, *根據一個對象的哈希碼就可以確定該對象應該存儲的哪個區域。 * * * HashSet就是采用哈希算法存取對象的集合,它內部采用對某個數字N進行取余的方式 *對哈希碼進行分組和劃分對象的存儲區域。Object類中定義一個hashCode()方法來返回每個Java *對象的哈希碼,當從HashSet集合中查找某個對象時,Java系統首先調用對象的hashCode()方法 *獲得該對象的哈希碼,然后根據哈希碼找到相應的存儲區域,最后取出該存儲區域內的每個元素與 *該對象進行equals方法比較,這樣不用遍歷集合中的所有元素就可以得到結論。可見,HashSet集合具有很好的對象 *檢索性能,但是,HashSet集合存儲對象的效率相對較低些,因為向HashSet集合中添加一個對象時, *要先計算出對象的哈希碼和根據這個哈希碼耵對象在集合中的存儲位置。 * * 為了保證一個類的實例對象能夠在HashSet正常存儲,要求這個類的兩個實例對象用equals() *方法比較的結果相等時,他們的哈希碼也必須相等。也就是說,如果obj1.equals(boj2)的結果為true, *那么以下表達式的結果也要為true。 obj1.hashCode()==obj2.hashCode() * * 如果一個類的hashCode方法沒有遵循上述要求,那么,當這個類的兩個實例對象用equals()方法 *比較的結果相等時,它們本來應該無法被同事存儲進Set集合中,但是,如果將他們存儲進HashSet *集合中時,由于它們的hashCode()方法的返回值不同,第二個對象首先按照哈希碼計算可能被放進與 *第一個對象不同的區域中,這樣,它就不可能與第一個對象進行equals方法比較了,這樣可能被存儲進 *HashSet集合中了。Object類中的hashCode()方法不能滿足對象被列入到HashSet中的要求,因為它的返回值 *都是通過對象的內存地址推算出來的,同一個對象在程序運行期間的任何時候返回的哈希值都是始終不變的,所以, *只要是兩個不同的實例對象,即使它們equals方法比較結果相等,它們默認的hashCode方法的返回值是不同的。 * *上面代碼ArrayList集合改為HashSet集合就可以看到這種錯誤的結果了,修改后的代碼: * *import java.util.HashSet; *class Ch15_Demo5{ * public static void main(String[] args){ * HashSet users=new HashSet(); * * users.add(new User("張三",28)); * users.add(new User("李四",28)); * users.add(new User("王五",28)); * System.out.println(users.size()); * * users.add(new User("張三",28)); * System.out.println(users.size()); *} * *} * * 只有類的實例對象要給采用哈希算法進行存儲和檢索時,這個類才需要按照要求覆蓋hashCode方法。即使程序 *可能暫時不會用到當前類的hashCode方法,但是為它提供一個hashCode方法也不會有什么不好,沒準以后什么時候又 *用到這個方法了,所以通常要求hashCode方法和equals方法一并被同時覆蓋。 * *提示: * (1)通常來說,一個類的兩個實例對象用equals()方法比較的結果相等時,它們的哈希碼也必須相等,但反之則不成立, * 即equals方法比較結果不相等的對象可以有相同的哈希碼,或者說哈希碼相同的兩個對象的equals方法比較的結果可以 * 不等,例如,字符串"BB"和"Aa"的equals方法比較結果可以不相等,但是它們的hashCode方法返回值卻相等。 * * (2)當一個對象被存儲進HashSet集合中以后,就不能修改這個對象中的那些參與計算哈希值的字段了,否則,對象修改后 * 的哈希值與最初存儲進HashSet集合中的哈希值就不同了,在這種情況下,即使在contains方法使用該對象當前應用作為參數去 * HashSet集合中檢索對象,也將返回找不到對象的結果,這也會導致無法從HashSet集合中單獨刪除當前對象,從而造成內存泄露。 * * * * */}
新聞熱點
疑難解答