深入理解equals和hashCode关系和区别
深入理解equals和hashCode關(guān)系和區(qū)別
- 直入主題:
- 區(qū)別:
- 1.他們判斷對(duì)象相同的方式不一樣:
- 2.他們判斷對(duì)象是否相等的準(zhǔn)確率不一樣:
- 改寫equals時(shí)總是要改寫hashcode
- 分享一波:程序員賺外快-必看的巔峰干貨
為什么要說equals和hashCode這兩個(gè)東西,一來是因?yàn)橛胁簧傩』锇槊嬖嚂r(shí)被問過這個(gè)東西,二來則是因?yàn)槿绻私饬诉@兩個(gè)東西的原理,那么實(shí)際的開發(fā)過程中,對(duì)效率和容錯(cuò)率上還是能幫上很大的忙!
直入主題:
很多人把他們放在一起比較,那我們首先要想到的是,他們肯定有大致相同的作用,和一些細(xì)小的區(qū)別。
先說說他們相同的作用:equals和hashCode方法都是用來判斷兩個(gè)對(duì)象的值是否相等,請(qǐng)記住這里說的相等僅僅說的是兩個(gè)對(duì)象的值,和他們的引用無關(guān)
區(qū)別:
1.他們判斷對(duì)象相同的方式不一樣:
2.他們判斷對(duì)象是否相等的準(zhǔn)確率不一樣:
為啥這樣說,因?yàn)閔ashCode有極小概率會(huì)判斷錯(cuò),而equals的判斷結(jié)果是百分百正確的
相信看到這里已經(jīng)有朋友有疑問了,既然hashCode方法不能準(zhǔn)確判斷,那我們?yōu)槭裁催€要用它?哈哈哈,因?yàn)槲覀儫o法忍受丟棄他的另一個(gè)優(yōu)點(diǎn),就是效率高,接著往下看,我們慢慢捋一捋。
先說上面的第一點(diǎn):判斷對(duì)象的相等的方式不一樣
1.equals:重寫的equals方法,比如String 的equals方法,如圖:
他最終的目的循環(huán)判斷兩個(gè)對(duì)象的每一個(gè)字符是否相等,所有字符全部對(duì)應(yīng)相等,那他們的值肯定也就相等了,這是equals的判斷方法
hashCode的判斷方法:hashCode是通過用hash算法來計(jì)算具體對(duì)象實(shí)例,得到斌返回一個(gè)hashcode值。通過比較hashcode值是否相等來判斷兩個(gè)對(duì)象是否相等,
相信大家看到這里是已經(jīng)有點(diǎn)懵逼了,別急,接下來具體講講他的原理:
以java.lang.Object來理解,JVM每new一個(gè)Object,它都會(huì)將這個(gè)Object丟到一個(gè)Hash哈希表中去,這樣的話,下次做Object的比較或者取這個(gè)對(duì)象的時(shí)候,它會(huì)根據(jù)對(duì)象的hashcode再從Hash表中取這個(gè)對(duì)象。這樣做的目的是提高取對(duì)象的效率。具體過程是這樣:
可能經(jīng)過上面理論的講一下大家都迷糊了,我也看了之后也是似懂非懂的。下面我舉個(gè)例子詳細(xì)說明下。
list是可以重復(fù)的,set是不可以重復(fù)的。那么set存儲(chǔ)數(shù)據(jù)的時(shí)候是怎樣判斷存進(jìn)的數(shù)據(jù)是否已經(jīng)存在。使用equals()方法呢,還是hashcode()方法。
假如用equals(),那么存儲(chǔ)一個(gè)元素就要跟已存在的所有元素比較一遍,比如已存入100個(gè)元素,那么存101個(gè)元素的時(shí)候,就要調(diào)用equals方法100次。
但如果用hashcode()方法的話,他就利用了hash算法來存儲(chǔ)數(shù)據(jù)的。
這樣的話每存一個(gè)數(shù)據(jù)就調(diào)用一次hashcode()方法,得到一個(gè)hashcode值及存入的位置。如果該位置不存在數(shù)據(jù)那么就直接存入,否則調(diào)用一次equals()方法,不相同則存,相同不存。這樣下來整個(gè)存儲(chǔ)下來不需要調(diào)用幾次equals方法,雖然多了幾次hashcode方法,但相對(duì)于前面來講效率高了不少。
上面開始的時(shí)候我著重說了重寫的equals方法,為什么要重寫呢?
因?yàn)镺bject的equal方法默認(rèn)是兩個(gè)對(duì)象的引用的比較,意思就是指向同一內(nèi)存,地址則相等,否則不相等;如果你現(xiàn)在需要利用對(duì)象里面的值來判斷是否相等,則重載equal方法。
說道這個(gè)地方我相信很多人會(huì)有疑問,相信大家都被String對(duì)象的equals()方法和"= ="糾結(jié)過一段時(shí)間,當(dāng)時(shí)我們知道String對(duì)象中equals方法是判斷值的,而= =是地址判斷。
那照這么說equals怎么會(huì)是地址的比較呢?
那是因?yàn)閷?shí)際上JDK中,String、Math等封裝類都對(duì)Object中的equals()方法進(jìn)行了重寫。
我們先看看Object中equals方法的源碼:
我們都知道所有的對(duì)象都擁有標(biāo)識(shí)(內(nèi)存地址)和狀態(tài)(數(shù)據(jù)),同時(shí)“==”比較兩個(gè)對(duì)象的的內(nèi)存地址,所以說使用Object的equals()方法是比較兩個(gè)對(duì)象的內(nèi)存地址是否相等,即若object1.equals(object2)為true,則表示equals1和equals2實(shí)際上是引用同一個(gè)對(duì)象。雖然有時(shí)候Object的equals()方法可以滿足我們一些基本的要求,但是我們必須要清楚我們很大部分時(shí)間都是進(jìn)行兩個(gè)對(duì)象的比較,這個(gè)時(shí)候Object的equals()方法就不可以了,所以才會(huì)有String這些類對(duì)equals方法的改寫,依次類推Double、Integer、Math。。。。等等這些類都是重寫了equals()方法的,從而進(jìn)行的是內(nèi)容的比較。希望大家不要搞混了。
改寫equals時(shí)總是要改寫hashcode
java.lnag.Object中對(duì)hashCode的約定:
根據(jù)上一個(gè)問題,實(shí)際上我們已經(jīng)能很簡(jiǎn)單的解釋這一點(diǎn)了,比如改寫String中的equals為基于內(nèi)容上的比較而不是內(nèi)存地址的話,那么雖然equals相等,但并不代表內(nèi)存地址相等,由hashcode方法的定義可知內(nèi)存地址不同,沒改寫的hashcode值也可能不同。所以違背了第二條約定。
又如new一個(gè)對(duì)象,再new一個(gè)內(nèi)容相等的對(duì)象,調(diào)用equals方法返回的true,但他們的hashcode值不同,將兩個(gè)對(duì)象存入HashSet中,會(huì)使得其中包含兩個(gè)相等的對(duì)象,因?yàn)槭窍葯z索hashcode值,不等的情況下才會(huì)去比較equals方法的。
原創(chuàng)文章,轉(zhuǎn)載請(qǐng)標(biāo)明出處
分享一波:程序員賺外快-必看的巔峰干貨
總結(jié)
以上是生活随笔為你收集整理的深入理解equals和hashCode关系和区别的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 启动TOMCAT报错 java.util
- 下一篇: Mybatis源码阅读(二):动态节点解