<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    我思故我強(qiáng)

    解析Java對(duì)象的equals()和hashCode()的使用

    前言

    在Java語(yǔ)言中,equals()和hashCode()兩個(gè)函數(shù)的使用是緊密配合的,你要是自己設(shè)計(jì)其中一個(gè),就要設(shè)計(jì)另外一個(gè)。在多數(shù)情況 下,這兩個(gè)函數(shù)是不用考慮的,直接使用它們的默認(rèn)設(shè)計(jì)就可以了。但是在一些情況下,這兩個(gè)函數(shù)最好是自己設(shè)計(jì),才能確保整個(gè)程序的正常運(yùn)行。最常見(jiàn)的是當(dāng) 一個(gè)對(duì)象被加入集合對(duì)象(collection object)時(shí),這兩個(gè)函數(shù)必須自己設(shè)計(jì)。更細(xì)化的定義是:如果你想將一個(gè)對(duì)象A放入另一個(gè)Collection Object B里,或者使用這個(gè)對(duì)象A為查找一個(gè)元對(duì)象在Collection Object    B里位置的key,并支持是否容納,刪除Collection Object    B里的元對(duì)象這樣的操作,那么,equals()和hashCode()函數(shù)必須開(kāi)發(fā)者自己定義。其他情 況下,這兩個(gè)函數(shù)是不需要定義的。

    equals():
    它是用于進(jìn)行兩個(gè)對(duì)象的比較的,是對(duì)象內(nèi)容的比較,當(dāng)然也能用于進(jìn)行對(duì)象參閱值的比較。什么是對(duì)象參閱值的比較?就是兩個(gè)參閱變量的值得比較,我們 都知道參閱變量的值其實(shí)就是一個(gè)數(shù)字,這個(gè)數(shù)字可以看成是鑒別不同對(duì)象的代號(hào)。兩個(gè)對(duì)象參閱值的比較,就是兩個(gè)數(shù)字的比較,兩個(gè)代號(hào)的比較。這種比較是默 認(rèn)的對(duì)象比較方式,在Object這個(gè)對(duì)象中,這種方式就已經(jīng)設(shè)計(jì)好了。所以你也不用自己來(lái)重寫,浪費(fèi)不必要的時(shí)間。

    對(duì)象內(nèi)容的比較才是設(shè)計(jì)equals()的真正目的,Java語(yǔ)言對(duì)equals()的要求如下,這些要求是必須遵循的。否則,你就不該浪費(fèi)時(shí)間:
    對(duì)稱性:如果x.equals(y)返回是“true”,那么y.equals(x)也應(yīng)該返回是“true”。
    反射性:x.equals(x)必須返回是“true”。
    類推性:如果x.equals(y)返回是“true”,而且y.equals(z)返回是“true”,那么z.equals(x)也應(yīng)該返回是“true”。
    還有一致性:如果x.equals(y)返回是“true”,只要x和y內(nèi)容一直不變,不管你重復(fù)x.equals(y)多少次,返回都是“true”。
    任何情況下,x.equals(null),永遠(yuǎn)返回是“false”;x.equals(和x不同類型的對(duì)象)永遠(yuǎn)返回是“false”。
    hashCode():
    這 個(gè)函數(shù)返回的就是一個(gè)用來(lái)進(jìn)行hash操作的整型代號(hào),請(qǐng)不要把這個(gè)代號(hào)和前面所說(shuō)的參閱變量所代表的代號(hào)弄混了。后者不僅僅是個(gè)代號(hào)還具有在內(nèi)存中才查找對(duì) 象的位置的功能。hashCode()所返回的值是用來(lái)分類對(duì)象在一些特定的Collection對(duì)象中的位置。這些對(duì)象是HashMap, Hashtable, HashSet,等等。這個(gè)函數(shù)和上面的equals()函數(shù)必須自己設(shè)計(jì),用來(lái)協(xié)助HashMap, Hashtable, HashSet,等等對(duì)自己所收集的大量對(duì)象進(jìn)行搜尋和定位。

    這些Collection對(duì)象究竟如何工作的,想象每個(gè)元對(duì)象hashCode是一個(gè)箱子的 編碼,按照編碼,每個(gè)元對(duì)象就是根據(jù)hashCode()提供的代號(hào)歸入相應(yīng)的箱子里。所有的箱子加起來(lái)就是一個(gè)HashSet,HashMap,或 Hashtable對(duì)象,我們需要尋找一個(gè)元對(duì)象時(shí),先看它的代碼,就是hashCode()返回的整型值,這樣我們找到它所在的箱子,然后在箱子里,每 個(gè)元對(duì)象都拿出來(lái)一個(gè)個(gè)和我們要找的對(duì)象進(jìn)行對(duì)比,如果兩個(gè)對(duì)象的內(nèi)容相等,我們的搜尋也就結(jié)束。這種操作需要兩個(gè)重要的信息,一是對(duì)象的 hashCode(),還有一個(gè)是對(duì)象內(nèi)容對(duì)比的結(jié)果。

    hashCode()的返回值和equals()的關(guān)系如下:

    如果x.equals(y)返回“true”,那么x和y的hashCode()必須相等。
    如果x.equals(y)返回“false”,那么x和y的hashCode()有可能相等,也有可能不等。

    為什么這兩個(gè)規(guī)則是這樣的,原因其實(shí)很簡(jiǎn)單,拿HashSet來(lái)說(shuō)吧,HashSet可以擁有一個(gè)或更多的箱子,在同一個(gè)箱子中可以有一個(gè) 或更多的獨(dú)特元對(duì)象(HashSet所容納的必須是獨(dú)特的元對(duì)象)。這個(gè)例子說(shuō)明一個(gè)元對(duì)象可以和其他不同的元對(duì)象擁有相同的hashCode。但是一個(gè) 元對(duì)象只能和擁有同樣內(nèi)容的元對(duì)象相等。所以這兩個(gè)規(guī)則必須成立。(在實(shí)際的某個(gè)集合對(duì)象如HashSet set.contains(object o);時(shí),是先通過(guò) hashcode()找到“箱子” ,在根據(jù) equals判斷對(duì)象內(nèi)容 是否相等,從而判斷集合對(duì)象是否包含某個(gè)元對(duì)象)

    設(shè)計(jì)這兩個(gè)函數(shù)所要注意到的:
    如果你設(shè)計(jì)的對(duì)象類型并不使用于Collection對(duì)象,那么沒(méi)有必要自己再設(shè)計(jì)這兩個(gè)函數(shù)的處理方式。這是正確的面向?qū)ο笤O(shè)計(jì)方法,任何用戶一時(shí)用不到的功能,就先不要設(shè)計(jì),以免給日后功能擴(kuò)展帶來(lái)麻煩。

    如果你在設(shè)計(jì)時(shí)想別出心裁,不遵守以上的兩套規(guī)則,那么勸你還是不要做這樣想入非非的事。我還沒(méi)有遇到過(guò)哪一個(gè)開(kāi)發(fā)者和我說(shuō)設(shè)計(jì)這兩個(gè)函數(shù)要違背前面說(shuō)的兩個(gè)規(guī)則,我碰到這些違反規(guī)則的情況時(shí),都是作為設(shè)計(jì)錯(cuò)誤處理。

    當(dāng)一個(gè)對(duì)象類型作為Collection對(duì)象的元對(duì)象時(shí),這個(gè)對(duì)象應(yīng)該擁有自己處理equals(),和/或處理hashCode()的設(shè)計(jì),而且要遵守前面所說(shuō) 的兩種原則。equals()先要查null和是否是同一類型。查同一類型是為了避免出現(xiàn)ClassCastException這樣的異常給丟出來(lái)。查 null是為了避免出現(xiàn)NullPointerException這樣的異常給丟出來(lái)。

    如果你的對(duì)象里面容納的數(shù)據(jù)過(guò)多,那么這兩個(gè)函數(shù) equals()和hashCode()將會(huì)變得效率低。如果對(duì)象中擁有無(wú)法serialized的數(shù)據(jù),equals()有可能在操作中出現(xiàn)錯(cuò)誤。想象 一個(gè)對(duì)象x,它的一個(gè)整型數(shù)據(jù)是transient型(不能被serialize成二進(jìn)制數(shù)據(jù)流)。然而equals()和hashCode()都有依靠 這個(gè)整型數(shù)據(jù),那么,這個(gè)對(duì)象在serialization之前和之后,是否一樣?答案是不一樣。因?yàn)閟erialization之前的整型數(shù)據(jù)是有效的 數(shù)據(jù),在serialization之后,這個(gè)整型數(shù)據(jù)的值并沒(méi)有存儲(chǔ)下來(lái),再重新由二進(jìn)制數(shù)據(jù)流轉(zhuǎn)換成對(duì)象后,兩者(對(duì)象在serialization 之前和之后)的狀態(tài)已經(jīng)不同了。這也是要注意的。

    知道以上這些能夠幫助你:
    1. 進(jìn)行更好的設(shè)計(jì)和開(kāi)發(fā)。
    2. 進(jìn)行更好的測(cè)試案例開(kāi)發(fā)。
    3. 在面試過(guò)程中讓面試者對(duì)你的學(xué)識(shí)淵博感到滿意。

    在Hibernate中,POJO類要重寫hashcode()方法和equals()方法。為什么呢?

    1,重點(diǎn)是equals,重寫hashCode只是技術(shù)要求(為了提高效率)

    2,為什么要重寫equals呢,因?yàn)樵趈ava的集合框架中,是通過(guò)equals來(lái)判斷兩個(gè)對(duì)象是否相等的

    3,在hibernate中,經(jīng)常使用set集合來(lái)保存相關(guān)對(duì)象,而set集合是不允許重復(fù)的,但是下面的程序,判斷一下運(yùn)行結(jié)果:

        Set user = new HashSet();
        user.add(new Book("精通struts"));
        user.add(new Book("精通struts"));
        System.out.println(user.size());

    上面程序的運(yùn)行結(jié)果取決于Book類是否重寫了equals方法。

    如果沒(méi)有重寫,默認(rèn)equals是比較地址,那么這兩個(gè)book對(duì)象不一樣,輸出2,意味著hibernate會(huì)認(rèn)為這是兩個(gè)對(duì)象,再接下來(lái)的持久化過(guò)程中可能會(huì)出錯(cuò)。

    如果重寫了equals,比如按照主鍵(書名)比較,那么這兩個(gè)對(duì)象是一樣的,輸出1 。


     

    posted on 2009-10-15 11:21 李云澤 閱讀(312) 評(píng)論(0)  編輯  收藏 所屬分類: 面試筆試相關(guān)的

    主站蜘蛛池模板: 亚洲麻豆精品国偷自产在线91| 免费99精品国产自在现线| 免费一看一级毛片全播放| 亚洲另类无码一区二区三区| 成人免费a级毛片| 国产AV旡码专区亚洲AV苍井空| 18禁无遮挡无码网站免费| 亚洲精品无码久久久久牙蜜区| 香蕉视频在线观看免费国产婷婷| 国产精品亚洲一区二区三区久久| 免费人成无码大片在线观看| 美女裸免费观看网站| 中文字幕久久亚洲一区| 最近免费中文字幕MV在线视频3| 亚洲天堂中文字幕| 久九九精品免费视频| 亚洲AV成人精品一区二区三区| 一本色道久久88综合亚洲精品高清| 日韩电影免费在线观看网址| 好看的电影网站亚洲一区| 91在线老王精品免费播放| 亚洲色大成网站www尤物| 亚洲国产aⅴ综合网| 久久免费福利视频| 亚洲人成77777在线观看网| 波多野结衣中文一区二区免费 | 国产亚洲一区区二区在线| 久久午夜伦鲁片免费无码| 亚洲性无码AV中文字幕| JLZZJLZZ亚洲乱熟无码| 84pao强力永久免费高清| 国产综合激情在线亚洲第一页| 中文字幕亚洲无线码| 日韩免费精品视频| 无遮挡国产高潮视频免费观看| 亚洲AV日韩AV永久无码绿巨人| 毛片大全免费观看| 99久久婷婷免费国产综合精品| 亚洲国产91在线| 亚洲亚洲人成综合网络| 中文字幕人成无码免费视频|