Java中equals,hashcode和==的區(qū)別

1、==

java中的數(shù)據(jù)類型亭病,可分為兩類:

  • 基本數(shù)據(jù)類型,也稱原始數(shù)據(jù)類型

byte,short,char,int,long,float,double,boolean 他們之間的比較嘶居,應(yīng)用雙等號(hào)(==),比較的是他們的值罪帖。

  • 引用類型(類、接口邮屁、數(shù)組)

當(dāng)他們用(==)進(jìn)行比較的時(shí)候整袁,比較的是他們?cè)趦?nèi)存中的存放地址,所以佑吝,除非是同一個(gè)new出來(lái)的對(duì)象坐昙,他們的比較后的結(jié)果為true,否則比較后結(jié)果為false芋忿。

對(duì)象是放在堆中的炸客,棧中存放的是對(duì)象的引用(地址)。由此可見(jiàn)'=='是對(duì)棧中的值進(jìn)行比較的戈钢。如果要比較堆中對(duì)象的內(nèi)容是否相同痹仙,那么就要重寫equals方法了。

例:

public static void main(String[] args) {  
        int int1 = 12;  
        int int2 = 12;  

        Integer Integer1 = new Integer(12);  
        Integer Integer2 = new Integer(12);  
        Integer Integer3 = new Integer(127);  

        Integer a1 = 127;  
        Integer b1 = 127;  

        Integer a = 128;  
        Integer b = 128;    

        String s1 = "str";  
        String s2 = "str";  

        String str1 = new String("str");  
        String str2 = new String("str");   

        System.out.println("int1==int2:" + (int1 == int2));  
        System.out.println("int1==Integer1:" + (int1 == Integer1));  
        System.out.println("Integer1==Integer2:" + (Integer1 == Integer2));  
        System.out.println("Integer3==b1:" + (Integer3 == b1));  
        System.out.println("a1==b1:" + (a1 == b1));  
        System.out.println("a==b:" + (a == b));  
        System.out.println("s1==s2:" + (s1 == s2));  
        System.out.println("s1==str1:" + (s1 == str1));  
        System.out.println("str1==str2:" + (str1 == str2));  
    }  

輸出結(jié)果:

int1==int2:true
int1==Integer1:true //Integer會(huì)自動(dòng)拆箱為int殉了,所以為true
Integer1==Integer2:false//不同對(duì)象开仰,在內(nèi)存存放地址不同,所以為false
Integer3==b1:false//Integer3指向new的對(duì)象地址,b1指向緩存中127地址抖所,地址不同梨州,所以為false

a1==b1:true
a==b:false

s1==s2:true
s1==str1:false
str1==str2:false

Integer b1 = 127;java在編譯的時(shí)候,被翻譯成-> Integer b1 = Integer.valueOf(127);

public static Integer valueOf(int i) {  
         assert IntegerCache.high >= 127;  
         if (i >= IntegerCache.low && i <= IntegerCache.high)  
             return IntegerCache.cache[i + (-IntegerCache.low)];  
         return new Integer(i);  
     }  

看一下源碼大家都會(huì)明白,對(duì)于-128到127之間的數(shù)田轧,會(huì)進(jìn)行緩存暴匠,Integer b1 = 127時(shí),會(huì)將127進(jìn)行緩存傻粘,下次再寫Integer i6 = 127時(shí)每窖,就會(huì)直接從緩存中取,就不會(huì)new了弦悉。所以a1==b1:true a==b:false

2窒典、equals

  • 默認(rèn)情況(沒(méi)有覆蓋equals方法)下equals方法都是調(diào)用Object類的equals方法,而Object的equals方法主要用于判斷對(duì)象的內(nèi)存地址引用是不是同一個(gè)地址(是不是同一個(gè)對(duì)象)稽莉。下面是Object類中equals方法:
public boolean equals(Object obj) {  
    return (this == obj);  
    }  

定義的equals與==是等效的

  • 要是類中覆蓋了equals方法瀑志,那么就要根據(jù)具體的代碼來(lái)確定equals方法的作用了,覆蓋后一般都是通過(guò)對(duì)象的內(nèi)容是否相等來(lái)判斷對(duì)象是否相等污秆。下面是String類對(duì)equals進(jìn)行了重寫:
public boolean equals(Object anObject) {  
    if (this == anObject) {  
        return true;  
    }  
    if (anObject instanceof String) {  
        String anotherString = (String)anObject;  
        int n = count;  
        if (n == anotherString.count) {  
        char v1[] = value;  
        char v2[] = anotherString.value;  
        int i = offset;  
        int j = anotherString.offset;  
        while (n-- != 0) {  
            if (v1[i++] != v2[j++])  
            return false;  
        }  
        return true;  
        }  
    }  
    return false;  
    }  

即String中equals方法判斷相等的步驟是:

1.若A==B 即是同一個(gè)String對(duì)象 返回true
2.若對(duì)比對(duì)象是String類型則繼續(xù)劈猪,否則返回false
3.判斷A、B長(zhǎng)度是否一樣良拼,不一樣的話返回false
4.逐個(gè)字符比較战得,若有不相等字符,返回false

這里對(duì)equals重新需要注意五點(diǎn):

1 自反性:對(duì)任意引用值X庸推,x.equals(x)的返回值一定為true.
2 對(duì)稱性:對(duì)于任何引用值x,y,當(dāng)且僅當(dāng)y.equals(x)返回值為true時(shí)常侦,x.equals(y)的返回值一定為true;
3 傳遞性:如果x.equals(y)=true, y.equals(z)=true,則x.equals(z)=true
4 一致性:如果參與比較的對(duì)象沒(méi)任何改變,則對(duì)象比較的結(jié)果也不應(yīng)該有任何改變
5 非空性:任何非空的引用值X贬媒,x.equals(null)的返回值一定為false

實(shí)現(xiàn)高質(zhì)量equals方法的訣竅:

1.使用==符號(hào)檢查“參數(shù)是否為這個(gè)對(duì)象的引用”聋亡。如果是,則返回true际乘。這只不過(guò)是一種性能優(yōu)化坡倔,如果比較操作有可能很昂貴,就值得這么做蚓庭。
2.使用instanceof操作符檢查“參數(shù)是否為正確的類型”致讥。如果不是,則返回false器赞。一般來(lái)說(shuō)垢袱,所謂“正確的類型”是指equals方法所在的那個(gè)類。
3.把參數(shù)轉(zhuǎn)換成正確的類型港柜。因?yàn)檗D(zhuǎn)換之前進(jìn)行過(guò)instanceof測(cè)試请契,所以確保會(huì)成功咳榜。
4.對(duì)于該類中的每個(gè)“關(guān)鍵”域,檢查參數(shù)中的域是否與該對(duì)象中對(duì)應(yīng)的域相匹配爽锥。如果這些測(cè)試全部成功涌韩,則返回true;否則返回false。
5.當(dāng)編寫完成了equals方法之后氯夷,檢查“對(duì)稱性”臣樱、“傳遞性”、“一致性”腮考。

3雇毫、hashCode

hashCode()方法返回的就是一個(gè)數(shù)值,從方法的名稱上就可以看出踩蔚,其目的是生成一個(gè)hash碼棚放。hash碼的主要用途就是在對(duì)對(duì)象進(jìn)行散列的時(shí)候作為key輸入,據(jù)此很容易推斷出馅闽,我們需要每個(gè)對(duì)象的hash碼盡可能不同飘蚯,這樣才能保證散列的存取性能。事實(shí)上福也,Object類提供的默認(rèn)實(shí)現(xiàn)確實(shí)保證每個(gè)對(duì)象的hash碼不同(在對(duì)象的內(nèi)存地址基礎(chǔ)上經(jīng)過(guò)特定算法返回一個(gè)hash碼)局骤。Java采用了哈希表的原理。哈希(Hash)實(shí)際上是個(gè)人名拟杉,由于他提出一哈希算法的概念庄涡,所以就以他的名字命名了量承。 哈希算法也稱為散列算法搬设,是將數(shù)據(jù)依特定算法直接指定到一個(gè)地址上。初學(xué)者可以這樣理解撕捍,hashCode方法實(shí)際上返回的就是對(duì)象存儲(chǔ)的物理地址(實(shí)際可能并不是)拿穴。

散列函數(shù),散列算法,哈希函數(shù)。
是一種從任何一種數(shù)據(jù)中創(chuàng)建小的數(shù)字“指紋”的方法忧风。
散列函數(shù)將任意長(zhǎng)度的二進(jìn)制值映射為較短的固定長(zhǎng)度的二進(jìn)制值默色,這個(gè)小的二進(jìn)制值稱為哈希值。
好的散列函數(shù)在輸入域中很少出現(xiàn)散列沖突狮腿。
=================================================================================
所有散列函數(shù)都有如下一個(gè)基本特性:

1:如果a=b腿宰,則h(a) = h(b)。
2:如果a!=b缘厢,則h(a)與h(b)可能得到相同的散列值吃度。

Object 的hashCode方法:返回一個(gè)int類型

public native int hashCode();

hashCode的作用

想要明白,必須要先知道Java中的集合贴硫〈幻浚  
總的來(lái)說(shuō)伊者,Java中的集合(Collection)有兩類,一類是List间护,再有一類是Set亦渗。前者集合內(nèi)的元素是有序的,元素可以重復(fù)汁尺;后者元素?zé)o序法精,但元素不可重復(fù)。

那么這里就有一個(gè)比較嚴(yán)重的問(wèn)題了:要想保證元素不重復(fù)痴突,可兩個(gè)元素是否重復(fù)應(yīng)該依據(jù)什么來(lái)判斷呢亿虽?

這就是Object.equals方法了。但是苞也,如果每增加一個(gè)元素就檢查一次洛勉,那么當(dāng)元素很多時(shí),后添加到集合中的元素比較的次數(shù)就非常多了如迟。也就是說(shuō)收毫,如果集合中現(xiàn)在已經(jīng)有1000個(gè)元素,那么第1001個(gè)元素加入集合時(shí)殷勘,它就要調(diào)用1000次equals方法此再。這顯然會(huì)大大降低效率。
于是玲销,Java采用了哈希表的原理输拇。

這樣一來(lái),當(dāng)集合要添加新的元素時(shí)贤斜,

先調(diào)用這個(gè)元素的hashCode方法策吠,就一下子能定位到它應(yīng)該放置的物理位置上。

如果這個(gè)位置上沒(méi)有元素瘩绒,它就可以直接存儲(chǔ)在這個(gè)位置上猴抹,不用再進(jìn)行任何比較了;

如果這個(gè)位置上已經(jīng)有元素了锁荔,就調(diào)用它的equals方法與新元素進(jìn)行比較蟀给,相同的話就不存,不相同就散列其它的地址阳堕。所以這里存在一個(gè)沖突解決的問(wèn)題跋理。這樣一來(lái)實(shí)際調(diào)用equals方法的次數(shù)就大大降低了,幾乎只需要一兩次恬总。

4前普、eqauls方法和hashCode方法關(guān)系

Java對(duì)于eqauls方法和hashCode方法是這樣規(guī)定的:

(1)同一對(duì)象上多次調(diào)用hashCode()方法,總是返回相同的整型值越驻。
(2)如果a.equals(b)汁政,則一定有a.hashCode() 一定等于 b.hashCode()道偷。
(3)如果!a.equals(b),則a.hashCode() 不一定等于 b.hashCode()记劈。此時(shí)如果a.hashCode() 總是不等于 b.hashCode()勺鸦,會(huì)提高h(yuǎn)ashtables的性能。
(4)a.hashCode()==b.hashCode() 則 a.equals(b)可真可假
(5)a.hashCode()目木!= b.hashCode() 則 a.equals(b)為假换途。

上面結(jié)論簡(jiǎn)記:

1、如果兩個(gè)對(duì)象equals刽射,Java運(yùn)行時(shí)環(huán)境會(huì)認(rèn)為他們的hashcode一定相等军拟。
2、如果兩個(gè)對(duì)象不equals誓禁,他們的hashcode有可能相等懈息。
3、如果兩個(gè)對(duì)象hashcode相等摹恰,他們不一定equals辫继。
4、如果兩個(gè)對(duì)象hashcode不相等俗慈,他們一定不equals姑宽。

關(guān)于這兩個(gè)方法的重要規(guī)范:

規(guī)范1:若重寫equals(Object obj)方法,有必要重寫hashcode()方法闺阱,確保通過(guò)equals(Object obj)方法判斷結(jié)果為true的兩個(gè)對(duì)象具備相等的hashcode()返回值炮车。說(shuō)得簡(jiǎn)單點(diǎn)就是:“如果兩個(gè)對(duì)象相同,那么他們的hashcode應(yīng)該相等”酣溃。不過(guò)請(qǐng)注意:這個(gè)只是規(guī)范瘦穆,如果你非要寫一個(gè)類讓equals(Object obj)返回true而hashcode()返回兩個(gè)不相等的值,編譯和運(yùn)行都是不會(huì)報(bào)錯(cuò)的救拉。不過(guò)這樣違反了Java規(guī)范难审,程序也就埋下了BUG瘫拣。

規(guī)范2:如果equals(Object obj)返回false亿絮,即兩個(gè)對(duì)象“不相同”,并不要求對(duì)這兩個(gè)對(duì)象調(diào)用hashcode()方法得到兩個(gè)不相同的數(shù)麸拄。說(shuō)的簡(jiǎn)單點(diǎn)就是:“如果兩個(gè)對(duì)象不相同派昧,他們的hashcode可能相同”。

5拢切、為什么覆蓋equals時(shí)總要覆蓋hashCode

一個(gè)很常見(jiàn)的錯(cuò)誤根源在于沒(méi)有覆蓋hashCode方法蒂萎。在每個(gè)覆蓋了equals方法的類中,也必須覆蓋hashCode方法淮椰。如果不這樣做的話五慈,就會(huì)違反Object.hashCode的通用約定纳寂,從而導(dǎo)致該類無(wú)法結(jié)合所有基于散列的集合一起正常運(yùn)作,這樣的集合包括HashMap泻拦、HashSet和Hashtable毙芜。

(1).在應(yīng)用程序的執(zhí)行期間,只要對(duì)象的equals方法的比較操作所用到的信息沒(méi)有被修改争拐,那么對(duì)這同一個(gè)對(duì)象調(diào)用多次腋粥,hashCode方法都必須始終如一地返回同一個(gè)整數(shù)。在同一個(gè)應(yīng)用程序的多次執(zhí)行過(guò)程中架曹,每次執(zhí)行所返回的整數(shù)可以不一致隘冲。
(2).如果兩個(gè)對(duì)象根據(jù)equals()方法比較是相等的,那么調(diào)用這兩個(gè)對(duì)象中任意一個(gè)對(duì)象的hashCode方法都必須產(chǎn)生同樣的整數(shù)結(jié)果绑雄。
(3).如果兩個(gè)對(duì)象根據(jù)equals()方法比較是不相等的展辞,那么調(diào)用這兩個(gè)對(duì)象中任意一個(gè)對(duì)象的hashCode方法,則不一定要產(chǎn)生相同的整數(shù)結(jié)果万牺。但是程序員應(yīng)該知道纵竖,給不相等的對(duì)象產(chǎn)生截然不同的整數(shù)結(jié)果,有可能提高散列表的性能杏愤。

6靡砌、總結(jié):

1、equals方法用于比較對(duì)象的內(nèi)容是否相等(覆蓋以后)

2珊楼、hashcode方法只有在集合中用到

3通殃、當(dāng)覆蓋了equals方法時(shí),比較對(duì)象是否相等將通過(guò)覆蓋后的equals方法進(jìn)行比較(判斷對(duì)象的內(nèi)容是否相等)厕宗。

4画舌、將對(duì)象放入到集合中時(shí),首先判斷要放入對(duì)象的hashcode值與集合中的任意一個(gè)元素的hashcode值是否相等已慢,如果不相等直接將該對(duì)象放入集合中曲聂。如果hashcode值相等,然后再通過(guò)equals方法判斷要放入對(duì)象與集合中的任意一個(gè)對(duì)象是否相等佑惠,如果equals判斷不相等朋腋,直接將該元素放入到集合中,否則不放入膜楷。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末旭咽,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子赌厅,更是在濱河造成了極大的恐慌穷绵,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,539評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件特愿,死亡現(xiàn)場(chǎng)離奇詭異仲墨,居然都是意外死亡勾缭,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門目养,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)漫拭,“玉大人,你說(shuō)我怎么就攤上這事混稽〔勺ぃ” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 165,871評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵匈勋,是天一觀的道長(zhǎng)礼旅。 經(jīng)常有香客問(wèn)我,道長(zhǎng)洽洁,這世上最難降的妖魔是什么痘系? 我笑而不...
    開(kāi)封第一講書人閱讀 58,963評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮饿自,結(jié)果婚禮上汰翠,老公的妹妹穿的比我還像新娘。我一直安慰自己昭雌,他們只是感情好复唤,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,984評(píng)論 6 393
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著烛卧,像睡著了一般佛纫。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上总放,一...
    開(kāi)封第一講書人閱讀 51,763評(píng)論 1 307
  • 那天呈宇,我揣著相機(jī)與錄音,去河邊找鬼局雄。 笑死甥啄,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的炬搭。 我是一名探鬼主播蜈漓,決...
    沈念sama閱讀 40,468評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼尚蝌!你這毒婦竟也來(lái)了迎变?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤飘言,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后驼侠,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體姿鸿,經(jīng)...
    沈念sama閱讀 45,850評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡谆吴,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,002評(píng)論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了苛预。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片句狼。...
    茶點(diǎn)故事閱讀 40,144評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖热某,靈堂內(nèi)的尸體忽然破棺而出腻菇,到底是詐尸還是另有隱情,我是刑警寧澤昔馋,帶...
    沈念sama閱讀 35,823評(píng)論 5 346
  • 正文 年R本政府宣布筹吐,位于F島的核電站,受9級(jí)特大地震影響秘遏,放射性物質(zhì)發(fā)生泄漏丘薛。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,483評(píng)論 3 331
  • 文/蒙蒙 一邦危、第九天 我趴在偏房一處隱蔽的房頂上張望洋侨。 院中可真熱鬧,春花似錦倦蚪、人聲如沸希坚。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,026評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)吏够。三九已至,卻和暖如春滩报,著一層夾襖步出監(jiān)牢的瞬間锅知,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,150評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工脓钾, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人可训。 一個(gè)月前我還...
    沈念sama閱讀 48,415評(píng)論 3 373
  • 正文 我出身青樓昌妹,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親握截。 傳聞我的和親對(duì)象是個(gè)殘疾皇子飞崖,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,092評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容