日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 人文社科 > 生活经验 >内容正文

生活经验

关于 hashcode 和 equals

發(fā)布時(shí)間:2023/11/27 生活经验 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 关于 hashcode 和 equals 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

首先需要明白 hashCode() 和equals是Object類(lèi)中已經(jīng)被定義好的,所以在java中定義的任何類(lèi)都有這兩個(gè)方法。其中原始的equals()方法是用來(lái)比較兩個(gè)對(duì)象的地址值,而原始的hashCode()方法返回其對(duì)象所在的物理地址。看下面一個(gè)例子:

   public static void main(String[] args) {Person person1 = new Person(10,"zhangsan");Person person2 = new Person(10,"zhangsan");System.out.println("pserson1 hasCode:" + person1.hashCode());System.out.println("pserson2 hasCode:" + person2.hashCode());System.out.println(person1.equals(person2));}
}
class Person{int age;String name;public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Person(int age, String name) {this.age = age;this.name = name;}

運(yùn)行結(jié)果如下:

?需要注意的一點(diǎn)是,equals()相等的兩個(gè)對(duì)象,hashCode()一定相等,hashCode()相等的話,并一定是相等的兩個(gè)對(duì)象,即equals并一定相等(我的理解是equals比較的是兩個(gè)對(duì)象,而hasCode()是對(duì)象的屬性,對(duì)象相等那么其屬性一定相等,相反其屬性相等但是并不一定是同一個(gè)對(duì)象)。這就要求我們?cè)谥貙?xiě)自定義類(lèi)的時(shí)候如果重寫(xiě)了equals()方法的話,一定也要重寫(xiě)hascode()方法。

同時(shí)我們知道Set集合是不允許有重復(fù)的內(nèi)容的。具體判斷set集合中是否有已經(jīng)有該對(duì)象的步驟如下:

1)、判斷兩個(gè)對(duì)象的hashCode是否相等 。
????? 如果不相等,認(rèn)為兩個(gè)對(duì)象也不相等,完畢?
????? 如果相等,轉(zhuǎn)入2)
(這一點(diǎn)只是為了提高存儲(chǔ)效率而要求的,其實(shí)理論上沒(méi)有也可以,但如果沒(méi)有,實(shí)際使用時(shí)效率會(huì)大大降低,所以我們這里將其做為必需的。)?
2)、判斷兩個(gè)對(duì)象用equals運(yùn)算是否相等 。
????? 如果不相等,認(rèn)為兩個(gè)對(duì)象也不相等?
????? 如果相等,認(rèn)為兩個(gè)對(duì)象相等(equals()是判斷兩個(gè)對(duì)象是否相等的關(guān)鍵)

如果想查找一個(gè)集合中是否包含有某個(gè)對(duì)象,大概的程序代碼怎樣寫(xiě)呢?
你通常是逐一取出每個(gè)元素與要查找的對(duì)象進(jìn)行比較,當(dāng)發(fā)現(xiàn)某個(gè)元素與要查找的對(duì)象進(jìn)行equals方法比較的結(jié)果相等時(shí),則停止繼續(xù)查找并返回肯定的信息,否則,返回否定的信息,如果一個(gè)集合中有很多個(gè)元素,比如有一萬(wàn)個(gè)元素,并且沒(méi)有包含要查找的對(duì)象時(shí),則意味著你的程序需要從集合中取出一萬(wàn)個(gè)元素進(jìn)行逐一比較才能得到結(jié)論。

有人發(fā)明了一種哈希算法來(lái)提高從集合中查找元素的效率,這種方式將集合分成若干個(gè)存儲(chǔ)區(qū)域,每個(gè)對(duì)象可以計(jì)算出一個(gè)哈希碼,可以將哈希碼分組(使用不同的hash函數(shù)來(lái)計(jì)算的),每組分別對(duì)應(yīng)某個(gè)存儲(chǔ)區(qū)域,根據(jù)一個(gè)對(duì)象的哈希嗎就可以確定該對(duì)象應(yīng)該存儲(chǔ)在哪個(gè)區(qū)域HashSet就是采用哈希算法存取對(duì)象的集合,它內(nèi)部采用對(duì)某個(gè)數(shù)字n進(jìn)行取余(這種的hash函數(shù)是最簡(jiǎn)單的)的方式對(duì)哈希碼進(jìn)行分組和劃分對(duì)象的存儲(chǔ)區(qū)域;Object類(lèi)中定義了一個(gè)hashCode()方法來(lái)返回每個(gè)Java對(duì)象的哈希碼,當(dāng)從HashSet集合中查找某個(gè)對(duì)象時(shí),Java系統(tǒng)首先調(diào)用對(duì)象的hashCode()方法獲得該對(duì)象的哈希碼表,然后根據(jù)哈希嗎找到相應(yīng)的存儲(chǔ)區(qū)域,最后取得該存儲(chǔ)區(qū)域內(nèi)的每個(gè)元素與該對(duì)象進(jìn)行equals方法比較;這樣就不用遍歷集合中的所有元素就可以得到結(jié)論,可見(jiàn),HashSet集合具有很好的對(duì)象檢索性能,但是,HashSet集合存儲(chǔ)對(duì)象的效率相對(duì)要低些,因?yàn)橄騂ashSet集合中添加一個(gè)對(duì)象時(shí),要先計(jì)算出對(duì)象的哈希碼和根據(jù)這個(gè)哈希碼確定對(duì)象在集合中的存放位置為了保證一個(gè)類(lèi)的實(shí)例對(duì)象能在HashSet正常存儲(chǔ),要求這個(gè)類(lèi)的兩個(gè)實(shí)例對(duì)象用equals()方法比較的結(jié)果相等時(shí),他們的哈希碼也必須相等;也就是說(shuō),如果obj1.equals(obj2)的結(jié)果為true,那么以下表達(dá)式的結(jié)果也要為true:
obj1.hashCode() == obj2.hashCode()
換句話說(shuō):當(dāng)我們重寫(xiě)一個(gè)對(duì)象的equals方法,就必須重寫(xiě)他的hashCode方法,不過(guò)不重寫(xiě)他的hashCode方法的話,Object對(duì)象中的hashCode方法始終返回的是一個(gè)對(duì)象的hash地址,而這個(gè)地址是永遠(yuǎn)不相等的。所以這時(shí)候即使是重寫(xiě)了equals方法,也不會(huì)有特定的效果的,因?yàn)閔ashCode方法如果都不想等的話,就不會(huì)調(diào)用equals方法進(jìn)行比較了,所以沒(méi)有意義了。

?

如果一個(gè)類(lèi)的hashCode()方法沒(méi)有遵循上述要求,那么,當(dāng)這個(gè)類(lèi)的兩個(gè)實(shí)例對(duì)象用equals()方法比較的結(jié)果相等時(shí),他們本來(lái)應(yīng)該無(wú)法被同時(shí)存儲(chǔ)進(jìn)set集合中,但是,如果將他們存儲(chǔ)進(jìn)HashSet集合中時(shí),由于他們的hashCode()方法的返回值不同(Object中的hashCode方法返回值是永遠(yuǎn)不同的),就是說(shuō)可能會(huì)被set保存兩次的。

看下面這個(gè)例子:

public static void main(String[] args) {Person person1 = new Person(10,"zhangsan");Person person2 = new Person(10,"zhangsan");System.out.println("pserson1 hasCode:" + person1.hashCode());System.out.println("pserson2 hasCode:" + person2.hashCode());System.out.println(person1.equals(person2));Set<Person> set = new HashSet<Person>();set.add(person1);set.add(person2);System.out.println(set.size());}
}
class Person{int age;String name;public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Person(int age, String name) {this.age = age;this.name = name;}@Overridepublic boolean equals(Object o){Person a = (Person) o;return a.name.equals(name) ;}//@Override//public int hashCode(){//    return 1;//}

?

這里面我們只是重寫(xiě)了equals方法,調(diào)用?person1.equals(person2) 也是返回true的,但是最終set.size()是2。這是運(yùn)行結(jié)果

我們?cè)傩薷囊幌吕?#xff0c;重寫(xiě)一下 hascode方法

 @Overridepublic int hashCode(){return age + name.hashCode();}

?

再看一下結(jié)果

我們?cè)賮?lái)看一個(gè)有意思的事情,如果我們把equals直接返回false,那么再調(diào)用set.add(person1),那么按照我們以上的分析,先檢查hashCode() 是否相等,再調(diào)用equals()方法,那么這時(shí)候應(yīng)該返回 set.size() 為3,然而事情的真相真如我們分析的那樣么,先看運(yùn)行結(jié)果;

 public static void main(String[] args) {Person person1 = new Person(10,"zhangsan");Person person2 = new Person(10,"zhangsan");System.out.println("pserson1 hasCode:" + person1.hashCode());System.out.println("pserson2 hasCode:" + person2.hashCode());System.out.println(person1.equals(person2));Set<Person> set = new HashSet<Person>();set.add(person1);set.add(person2);set.add(person1);// System.out.println(person1 == person1);
        System.out.println(set.size());}
}
class Person{int age;String name;public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Person(int age, String name) {this.age = age;this.name = name;}@Overridepublic boolean equals(Object o){//Person a = (Person) o;//return a.name.equals(name) ;return false;}@Overridepublic int hashCode(){return age + name.hashCode();}

?

?

hashCode是基于hashMap實(shí)現(xiàn)的,我們查看一下hashMap的源碼查找一下原因

/*** Associates the specified value with the specified key in this map.* If the map previously contained a mapping for the key, the old* value is replaced.** @param key key with which the specified value is to be associated* @param value value to be associated with the specified key* @return the previous value associated with <tt>key</tt>, or*         <tt>null</tt> if there was no mapping for <tt>key</tt>.*         (A <tt>null</tt> return can also indicate that the map*         previously associated <tt>null</tt> with <tt>key</tt>.)*/public V put(K key, V value) {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;}

?分析一下?if (e.hash == hash && ((k = e.key) == key || key.equals(k))) 如果 hash一樣的話,會(huì)去判斷 key == key 和 key.equals(k),只要兩個(gè)有一個(gè)符合要求就插入不成功,而對(duì)于同一個(gè)對(duì)象來(lái)說(shuō) ?person1 == person1 永遠(yuǎn)是true,所以set里面還是2,當(dāng)然這種情況很少會(huì)遇到,一般重寫(xiě) equals()方法的時(shí)候不會(huì)直接返回 false~。如果非要讓set變成3個(gè)話也行,重寫(xiě)一下hashCode就可以了,比如我們可以產(chǎn)生一個(gè)隨機(jī)數(shù)?

 @Overridepublic int hashCode(){return (int)(Math.random()*100);}

?最后在看一個(gè)刪除時(shí)候應(yīng)該注意的地方:

public static void main(String[] args) {Person person1 = new Person(10, "zhangsan");Person person2 = new Person(10, "zhangsan");//System.out.println("pserson1 hasCode:" + person1.hashCode());//System.out.println("pserson2 hasCode:" + person2.hashCode());//System.out.println(person1.equals(person2));Set<Person> set = new HashSet<Person>();set.add(person1);set.add(person2);set.add(person1);System.out.println("刪除前set.size():" + set.size());System.out.println("更改屬性前person1.hashCode():" + person1.hashCode());person1.setAge(6);System.out.println("更改屬性后person1.hashCode():" + person1.hashCode());set.remove(person1);// System.out.println(person1 == person1);System.out.println("刪除后set.size():" + set.size());}

?運(yùn)行結(jié)果:

?事情又出乎我們的意料之外,我們明明已經(jīng)刪除了person1,但是事實(shí)上并沒(méi)有刪除成功,我在程序中已經(jīng)把原因打印出出來(lái)了,更改了屬性以后,因?yàn)槲覀兊膆ashCode()是根據(jù)屬性值來(lái)生成的,因此屬性更改以后hashCode()也被修改了但是他的存儲(chǔ)位置不會(huì)有變化,當(dāng)刪除的時(shí)候會(huì)按照新的hashCode()去找person1,肯定找不到,所以并沒(méi)有刪除成功,會(huì)導(dǎo)致失敗。

這告訴我們一個(gè)事情:如果對(duì)象的屬性值參與了hashCode的運(yùn)算中,在進(jìn)行刪除的時(shí)候,就不能對(duì)其屬性值進(jìn)行修改,否則會(huì)出現(xiàn)嚴(yán)重的問(wèn)題。

轉(zhuǎn)載于:https://www.cnblogs.com/l919310075/p/7376229.html

總結(jié)

以上是生活随笔為你收集整理的关于 hashcode 和 equals的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 午夜视频黄色 | 久久这里 | 伊人久久婷婷 | 久久爱综合网 | 青青草视频污 | 国产又粗又硬视频 | 国产在线观看免费播放 | 无码任你躁久久久久久久 | 久久一二三四区 | 午夜精品福利一区二区 | 黑人与日本少妇 | 亚洲hhh| 摸大乳喷奶水www视频 | 久久九精品 | 一级片视频免费观看 | 久久精品系列 | 久久在线视频 | 日本a视频| 青青青网 | 亚洲国产私拍精品国模在线观看 | 欧美成人免费在线视频 | av最新天堂 | www.色天使| 伊人久久爱 | 一区二区三区视频在线观看 | 日韩精品一区二区免费视频 | 亚洲一区二区中文字幕 | 国产日韩欧美精品在线观看 | 国产精品视频麻豆 | 欧美又粗又长又爽做受 | 午夜精品一区二区三区在线观看 | 依依成人综合网 | 日韩欧美91 | 大色网小色网 | 欧美日本免费 | 亚洲天堂av一区二区 | 操丰满女人| 国产女厕一区二区三区在线视 | 中文字幕丰满孑伦无码专区 | 亚洲国产日本 | 午夜天堂在线观看 | 中文字幕一区二区三区精华液 | 日本三级视频在线 | av香蕉| 日本打白嫩屁股视频 | 亚洲a∨无码无在线观看 | 欧美网站在线观看 | 四虎www | 草莓巧克力香氛动漫的观看方法 | 精品少妇人妻av免费久久久 | 日本不卡高字幕在线2019 | 日韩一区二区三区在线看 | 清纯唯美亚洲激情 | 欧美1314 | 极品美妇后花庭翘臀娇吟小说 | 在线看片你懂的 | 国产日韩久久 | 五月婷婷综合在线 | 日本xxxwww| 天天碰视频 | 国产理论视频 | 日韩在线不卡视频 | 国产男男gay体育生白袜 | 亚洲产国偷v产偷v自拍涩爱 | 青娱网电信一区电信二区电信三区 | 久久精品综合网 | 国产又粗又猛又色 | 自拍三区| www.久久艹 | jizzjizzjizz国产 | 国产午夜福利一区 | 国产精品久久久久久久久久久久久久 | а天堂中文在线官网 | 国产污视频在线看 | 青草av在线 | 久久久麻豆 | 人妻少妇偷人精品久久性色 | 中文字幕 日本 | 久久伊人网站 | 亚洲精品18p | 日本色网址 | 国产黄色在线免费观看 | 人人人爽 | 亚洲中文无码久久 | 日本系列第一页 | 国产精品成人午夜视频 | 国产黄色一区二区 | 免费淫片 | 成人妇女淫片aaaa视频 | 色中文网 | 一级片免费视频 | 午夜成年视频 | 五月天婷婷丁香花 | 亚洲毛片大全 | 美国伊人网 | 精品亚洲永久免费精品 | xxxxx黄色 | 亚洲 欧美 日韩在线 | 日本一区成人 |