摘要:而這次在一的一方實(shí)體里重寫基類的和方法做去重,感覺用的代碼量減少了,又能提高效率,所以我這里對這兩個(gè)方法做些自己的理解。不相等的兩個(gè)對象,不一定不相等。不相等,那么是一定不等的。文章若有錯(cuò)誤之處,歡迎指出。
昨天寫hibernate一對多查詢的時(shí)候,用set集合來儲存值,
我們都知道java中List集合是有序,可重復(fù)的,Set集合是無序,不可重復(fù)的。所以當(dāng)時(shí)寫這個(gè)查詢的時(shí)候果斷用Set來存值,但還是出現(xiàn)了值重復(fù)問題。
具體請看SF上提問:https://segmentfault.com/q/10...
我之前做的在for里對set有去重做法,但是有不足之處的。而這次在“一”的一方實(shí)體里重寫Object基類的hashCode和equals方法做去重,感覺用的代碼量減少了,又能提高效率,所以我這里對這兩個(gè)方法做些自己的理解。
1、hashCode()和equals()是什么
hashCode和equals方法是在Object基類中,所以每個(gè)對象都可以重寫這兩個(gè)方法,
看看JDK中這兩個(gè)方法源碼
hashCode
/** * 查看hashCode源碼是native修飾的, 說明這個(gè)方法是個(gè)原生函數(shù), * 也就是說這個(gè)方法不是用java實(shí)現(xiàn)的,底層是用C/C++實(shí)現(xiàn)的 * 返回哈希值 */ public native int hashCode();
equals
/* 用來比較兩個(gè)引用所指向的對象內(nèi)存地址是否一致 */ public boolean equals(Object obj) { return (this == obj); }
2、hashCode()和equals()關(guān)系是什么?
明白幾個(gè)原則:
equals相等的兩個(gè)對象,hashcode一定相等。
equals不相等的兩個(gè)對象,hashcode不一定不相等。
hashcode不相等,那么equals是一定不等的。
hashcode相等,equals可能相等,也可能不等。
解釋下第四個(gè)原則:
就好比hashcode像是一個(gè)詞典目錄里的按字母為索引查找字,查一個(gè)“Z”拼音開頭的詞,下面等查到“自己”,“自我”,“知道”等詞,用equals就是判斷這些詞語當(dāng)中是否有相等的詞,“自己”和“知道”兩個(gè)詞不相等的,所以equals值不等,但它們同屬于"Z"開頭的詞所以它們hashcode值相等。
3、為什么重寫equals的同時(shí)也要重寫hashCode呢?
這個(gè)問題不難解釋,就像前面問題一樣,hash算法是為了提高equals比較的效率而被發(fā)明出來的。這點(diǎn)在集合方面就能體現(xiàn)出來,就比如在List或Set集合里要比較是否有重復(fù)元素,當(dāng)發(fā)現(xiàn)某個(gè)集合對象與另一個(gè)集合對象equals比較的結(jié)果相等時(shí),則停止查找返回true值,反之,返回false值。但如果集合中有大量元素呢,假設(shè)一個(gè)集合A里有10萬元素,而且另一個(gè)比較的對象B中還可能沒有重復(fù)的值,則意味著其實(shí)不用比較我都知道兩者不相同,但程序依然會對集合A里遍歷10萬元素然后和B進(jìn)行逐一排查。。。又或者當(dāng)我要加入第100001個(gè)數(shù)據(jù)我要驗(yàn)證前面元素有重復(fù)值,就要跟前面10萬個(gè)元素一一比較,效率可想而知很低。
而哈希算法就是Java系統(tǒng)首先調(diào)用對象的hashCode()方法獲得該對象的哈希碼表,然后根據(jù)哈希碼找到相應(yīng)的存儲區(qū)域,若哈希碼相同在取得該存儲區(qū)域內(nèi)的每個(gè)元素與該對象進(jìn)行equals方法比較,若不同也就沒有繼續(xù)比較的必要了,這對于數(shù)量較大的情況效率就提高了不少,重寫hashcode方法,最主要就是保證操作的元素在同一個(gè)對象里且值都沒有重復(fù),若沒有重寫hashcode,可能會出現(xiàn)將對象引用不同,但元素完全相同的集合進(jìn)行操作。
下面寫一個(gè)例子
package demo; public class override_HshCode_Equals { public int x; public int y; public override_HshCode_Equals(int x, int y) { 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; } /** * equals返回false就說明沒有重復(fù)項(xiàng)可以添加 * true是重復(fù)不能添加 */ @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; final override_HshCode_Equals heClass = (override_HshCode_Equals) obj; //這里就對實(shí)例化對象里的x,y進(jìn)行比較 if (x != heClass.x) { return false; } if (y != heClass.y) { return false; } return true; } }
測試類
package demo; import java.util.HashSet; public class TestMain { public static void main(String[] args) { HashSetset = new HashSet (); override_HshCode_Equals heClass1 = new override_HshCode_Equals(1, 1); override_HshCode_Equals heClass2 = new override_HshCode_Equals(5, 5); override_HshCode_Equals heClass3 = new override_HshCode_Equals(1, 1); set.add(heClass1); set.add(heClass2); set.add(heClass3); set.add(heClass1); System.out.println("set數(shù)量=" + set.size()); } }
結(jié)果如下
set數(shù)量=2
注:重寫override_HshCode_Equals類的hashCode相當(dāng)于自定義返回了一個(gè)“哈希碼”,對比x,y值是否相等,先比較hashcode值,heClass1(3,3)==heClass3(3,3),所以它們的hashcode值相等,但是heClass2的x,y和heClass1,heClass3的x,y值不等,所以hashcode不等,equals一定不等,所以heClass2對象是可以add進(jìn)去的。前面說了heClass1和heClass3的hashcode值相等,然后進(jìn)入equals進(jìn)行對比,發(fā)現(xiàn)兩者的對象都是相同的,根據(jù)程序add循序來看,所以heClass1是可以add進(jìn)去的,然后heClass3和后面add(heClass1)都為重復(fù)項(xiàng),就不會添加
注釋override_HshCode_Equals里的hashCode方法
結(jié)果如下
set數(shù)量=3
注:首先判斷heClass1對象和heClass2對象的hashCode,此時(shí)Object中的hashCode方法返回的是對象本地內(nèi)存地址的換算結(jié)果,不同的實(shí)例對象的hashCode是不相同的,同樣因?yàn)閔eClass3和heClass1的hashCode也是不相等的,但是后面第四個(gè)添加中heClass1==heClass1的,所以最后set集合中只有heClass1,heClass2,heClass3這三個(gè)對象。
修改:override_HshCode_Equals heClass3 = new override_HshCode_Equals(1, 2);
結(jié)果如下
set數(shù)量=3
注:此時(shí)對比heClass1,heClass2,heClass3的x,y值都不相同,hashcode值不同,而第四個(gè)添加heClass1=heClass1,故添加不進(jìn)去,set里有heClass1,heClass2,heClass3。
文章若有錯(cuò)誤之處,歡迎指出。
參考網(wǎng)站: http://www.cnblogs.com/ysch/p/4323889.html
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/70440.html
摘要:的工作原理是近年來常見的面試題。讓我們再來看看這些問題設(shè)計(jì)哪些知識點(diǎn)的概念中解決碰撞的方法和的應(yīng)用,以及它們在中的重要性不可變對象的好處多線程的條件競爭重新調(diào)整的大小總結(jié)的工作原理基于原理,我們通過和方法儲存和獲取對象。 HashMap 的工作原理是近年來常見的 Java 面試題。幾乎每個(gè) Java 程序員都知道 HashMap,都知道哪里要用 HashMap,知道Hashtable和...
摘要:根據(jù)的重新計(jì)算值。如果這兩個(gè)的通過比較返回,新添加的將覆蓋集合中原有的,但不會覆蓋。如果這兩個(gè)的通過比較返回,新添加的將與集合中原有形成鏈,而且新添加的位于鏈的頭部具體說明繼續(xù)看方法的說明。 關(guān)于hashCode hashCode的存在主要是用于查找的快捷性,如Hashtable,HashMap等,hashCode是用來在散列存儲結(jié)構(gòu)中確定對象的存儲地址的. 1.hashcode是用來...
摘要:最近看到上面的一篇博客面試必備最常見的面試題全解析講解了關(guān)于體系的一些模塊以及面試中的一些常見問題雖然最近沒有要去找工作的需求但是鞏固一下這方面的知識還是很有必要的后面從作者提出的問題進(jìn)行自我的提問與解答有問題歡迎大家指出基礎(chǔ)部分和的區(qū)別我 最近看到CSDN上面的一篇博客 面試必備:《Java最常見的200+面試題全解析》, 講解了關(guān)于Java體系的一些模塊以及面試中的一些常見問題; ...
摘要:當(dāng)容量超過容量負(fù)載因子時(shí),進(jìn)行擴(kuò)容操作確定何時(shí)將沖突的鏈表轉(zhuǎn)換成紅黑樹用來確何時(shí)將紅黑樹轉(zhuǎn)換成鏈表當(dāng)鏈表轉(zhuǎn)換成紅黑樹時(shí),需要判斷數(shù)組容量。桶排序核心思想是根據(jù)數(shù)據(jù)規(guī)模劃分,個(gè)相同大小的區(qū)間每個(gè)區(qū)間為一個(gè)桶,桶可理解為容器。 剛剛看到QQ群有人吹Hashmap,一想我啥都不懂,就趕快補(bǔ)了一波。下面分享一下我對Hashmap的理解,主要用于個(gè)人備忘。如果有不對,請批評。想要解鎖更多新姿勢?...
摘要:語言通過字節(jié)碼的方式,在一定程度上解決了傳統(tǒng)解釋型語言執(zhí)行效率低的問題,同時(shí)又保留了解釋型語言可移植的特點(diǎn)。有針對不同系統(tǒng)的特定實(shí)現(xiàn),,,目的是使用相同的字節(jié)碼,它們都會給出相同的結(jié)果。項(xiàng)目主要基于捐贈的源代碼。 本文來自于我的慕課網(wǎng)手記:Java編程中那些再熟悉不過的知識點(diǎn),轉(zhuǎn)載請保留鏈接 ;) 1. 面向?qū)ο蠛兔嫦蜻^程的區(qū)別 面向過程 優(yōu)點(diǎn): 性能比面向?qū)ο蟾摺R驗(yàn)轭愓{(diào)用時(shí)需要實(shí)例...
閱讀 3813·2021-10-12 10:11
閱讀 3637·2021-09-13 10:27
閱讀 2540·2019-08-30 15:53
閱讀 1972·2019-08-29 18:33
閱讀 2189·2019-08-29 14:03
閱讀 994·2019-08-29 13:27
閱讀 3316·2019-08-28 18:07
閱讀 763·2019-08-26 13:23