java中Object的hashCode()和equals()方法

hashCode()方法

首先來看看hashCode()在源代碼中的注釋(java8):

/**
     * Returns a hash code value for the object. This method is
     * supported for the benefit of hash tables such as those provided by
     * {@link java.util.HashMap}.
     * <p>
     * The general contract of {@code hashCode} is:
     * <ul>
     * <li>Whenever it is invoked on the same object more than once during
     *     an execution of a Java application, the {@code hashCode} method
     *     must consistently return the same integer, provided no information
     *     used in {@code equals} comparisons on the object is modified.
     *     This integer need not remain consistent from one execution of an
     *     application to another execution of the same application.
     * <li>If two objects are equal according to the {@code equals(Object)}
     *     method, then calling the {@code hashCode} method on each of
     *     the two objects must produce the same integer result.
     * <li>It is <em>not</em> required that if two objects are unequal
     *     according to the {@link java.lang.Object#equals(java.lang.Object)}
     *     method, then calling the {@code hashCode} method on each of the
     *     two objects must produce distinct integer results.  However, the
     *     programmer should be aware that producing distinct integer results
     *     for unequal objects may improve the performance of hash tables.
     * </ul>
     * <p>
     * As much as is reasonably practical, the hashCode method defined by
     * class {@code Object} does return distinct integers for distinct
     * objects. (This is typically implemented by converting the internal
     * address of the object into an integer, but this implementation
     * technique is not required by the
     * Java&trade; programming language.)
     *
     * @return  a hash code value for this object.
     * @see     java.lang.Object#equals(java.lang.Object)
     * @see     java.lang.System#identityHashCode
     */
    public native int hashCode();

作用是:為對象返回一個(gè)hash值润努,為支持哈希表提供了很好的支持舒帮。
hashCode的約定是:

  • 在一個(gè)java程序執(zhí)行期間,如果對象中用于等價(jià)比較的信息沒有改變咒锻,同一個(gè)對象無論何時(shí)超過一次執(zhí)行,該方法都返回相同的整數(shù)。這個(gè)哈希值在程序的一個(gè)執(zhí)行到該程序的另一個(gè)執(zhí)行不需要保持一致漓摩。
  • 如果兩個(gè)對象通過equals()判斷為相等的,那么調(diào)用兩個(gè)對象的hashCode()肯定也返回相同的值陈瘦。
  • 通過equals()方法判斷不相等的兩個(gè)對象的hash值并不意味是不同的幌甘。但是程序員要意識到不同對象產(chǎn)生不同的哈希值有助于提高哈希表的性能潮售。

最佳實(shí)踐是類中定義的hashCode方法,不同的對象返回不同的值锅风。(通常的實(shí)現(xiàn)是將對象的內(nèi)部地址轉(zhuǎn)換為一個(gè)值酥诽,但是這個(gè)技術(shù)實(shí)現(xiàn)不是java變成語言所必須的)

equals()方法

/**
     * Indicates whether some other object is "equal to" this one.
     * <p>
     * The {@code equals} method implements an equivalence relation
     * on non-null object references:
     * <ul>
     * <li>It is <i>reflexive</i>: for any non-null reference value
     *     {@code x}, {@code x.equals(x)} should return
     *     {@code true}.
     * <li>It is <i>symmetric</i>: for any non-null reference values
     *     {@code x} and {@code y}, {@code x.equals(y)}
     *     should return {@code true} if and only if
     *     {@code y.equals(x)} returns {@code true}.
     * <li>It is <i>transitive</i>: for any non-null reference values
     *     {@code x}, {@code y}, and {@code z}, if
     *     {@code x.equals(y)} returns {@code true} and
     *     {@code y.equals(z)} returns {@code true}, then
     *     {@code x.equals(z)} should return {@code true}.
     * <li>It is <i>consistent</i>: for any non-null reference values
     *     {@code x} and {@code y}, multiple invocations of
     *     {@code x.equals(y)} consistently return {@code true}
     *     or consistently return {@code false}, provided no
     *     information used in {@code equals} comparisons on the
     *     objects is modified.
     * <li>For any non-null reference value {@code x},
     *     {@code x.equals(null)} should return {@code false}.
     * </ul>
     * <p>
     * The {@code equals} method for class {@code Object} implements
     * the most discriminating possible equivalence relation on objects;
     * that is, for any non-null reference values {@code x} and
     * {@code y}, this method returns {@code true} if and only
     * if {@code x} and {@code y} refer to the same object
     * ({@code x == y} has the value {@code true}).
     * <p>
     * Note that it is generally necessary to override the {@code hashCode}
     * method whenever this method is overridden, so as to maintain the
     * general contract for the {@code hashCode} method, which states
     * that equal objects must have equal hash codes.
     *
     * @param   obj   the reference object with which to compare.
     * @return  {@code true} if this object is the same as the obj
     *          argument; {@code false} otherwise.
     * @see     #hashCode()
     * @see     java.util.HashMap
     */
    public boolean equals(Object obj) {
        return (this == obj);
    }
  • 自反性:對于任意非空引用x,x.equals(x)一定返回true
  • 對稱性:對于任意非空引用x,y皱埠,如果x.equals(y)返回true肮帐,那么y.equals(x)也一定返回true
  • 傳遞性:對于任意非空引用x,y,z,如果x.equals(y)返回true和y.equals(z)返回true边器,那么x.equals(z)也一定返回true
  • 一致性:對于任意非空引用x,y,如果對象中用于等價(jià)比較的信息沒有改變训枢,那么無論調(diào)用多少次x.equals(y)返回的結(jié)果都是一致的,要么是true忘巧,要么是false
  • 對任何不是null的x,x.equals(null)一定返回false

Object類的equals()方法實(shí)現(xiàn)的是最挑剔的可能等價(jià)的關(guān)系恒界。也就是說,對于任何非空引用x,y,當(dāng)且僅當(dāng)x,y引用于同一個(gè)對象才會返回true

需要注意的是砚嘴,當(dāng)該方法被重寫時(shí)通常需要重寫hashCode()方法十酣,符合hashCode()方法的約定,即平等對象必須有相同的哈希碼

為什么通常重寫equals還要重寫hashCode()的方法际长,因?yàn)樵趈ava集合類有關(guān)散列表的實(shí)現(xiàn)中耸采,通常不僅僅判斷equals方法,還會判斷hashCode()方法

public class User {
    private String name;
    private int age;
    public User(){}
    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        if (age != user.age) return false;
        return name != null ? name.equals(user.name) : user.name == null;
    }

    public static void main(String[] args) {
        Map<User,String> map = new HashMap<>();
        map.put(new User("a",1),"1");
        System.out.println(map.get(new User("a",1)));
    }

只重寫equals方法后工育,輸出為null,主要原因在于HashMap的判斷方法同時(shí)判斷hash值和equals(),
而一般默認(rèn)Object的hashCode()方法是映射于對象的存儲地址虾宇。

final Node<K,V> getNode(int hash, Object key) {
        Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
        if ((tab = table) != null && (n = tab.length) > 0 &&
            (first = tab[(n - 1) & hash]) != null) {
            //判斷
            if (first.hash == hash && // always check first node
                ((k = first.key) == key || (key != null && key.equals(k))))
                return first;
            if ((e = first.next) != null) {
                if (first instanceof TreeNode)
                    return ((TreeNode<K,V>)first).getTreeNode(hash, key);
                do {
                //判斷
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        return e;
                } while ((e = e.next) != null);
            }
        }
        return null;
    }

也重寫hashCode方法:

public class User {
    private String name;
    private int age;
    public User(){}
    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        if (age != user.age) return false;
        return name != null ? name.equals(user.name) : user.name == null;
    }

    @Override
    public int hashCode() {
        return name.hashCode()*37+age;
    }

    public static void main(String[] args) {
        Map<User,String> map = new HashMap<>();
        map.put(new User("a",1),"1");
        System.out.println(map.get(new User("a",1)));
    }
}

輸出的為1,是正確的

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末如绸,一起剝皮案震驚了整個(gè)濱河市嘱朽,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌竭沫,老刑警劉巖燥翅,帶你破解...
    沈念sama閱讀 211,743評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異蜕提,居然都是意外死亡森书,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評論 3 385
  • 文/潘曉璐 我一進(jìn)店門谎势,熙熙樓的掌柜王于貴愁眉苦臉地迎上來凛膏,“玉大人,你說我怎么就攤上這事脏榆〔粒” “怎么了?”我有些...
    開封第一講書人閱讀 157,285評論 0 348
  • 文/不壞的土叔 我叫張陵须喂,是天一觀的道長吁断。 經(jīng)常有香客問我趁蕊,道長,這世上最難降的妖魔是什么仔役? 我笑而不...
    開封第一講書人閱讀 56,485評論 1 283
  • 正文 為了忘掉前任掷伙,我火速辦了婚禮,結(jié)果婚禮上又兵,老公的妹妹穿的比我還像新娘任柜。我一直安慰自己,他們只是感情好沛厨,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,581評論 6 386
  • 文/花漫 我一把揭開白布宙地。 她就那樣靜靜地躺著,像睡著了一般逆皮。 火紅的嫁衣襯著肌膚如雪宅粥。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,821評論 1 290
  • 那天电谣,我揣著相機(jī)與錄音粹胯,去河邊找鬼。 笑死辰企,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的况鸣。 我是一名探鬼主播牢贸,決...
    沈念sama閱讀 38,960評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼镐捧!你這毒婦竟也來了潜索?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,719評論 0 266
  • 序言:老撾萬榮一對情侶失蹤懂酱,失蹤者是張志新(化名)和其女友劉穎竹习,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體列牺,經(jīng)...
    沈念sama閱讀 44,186評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡整陌,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,516評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了瞎领。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片泌辫。...
    茶點(diǎn)故事閱讀 38,650評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖九默,靈堂內(nèi)的尸體忽然破棺而出震放,到底是詐尸還是另有隱情,我是刑警寧澤驼修,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布殿遂,位于F島的核電站诈铛,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏墨礁。R本人自食惡果不足惜幢竹,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,936評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望饵溅。 院中可真熱鬧妨退,春花似錦、人聲如沸蜕企。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,757評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽轻掩。三九已至幸乒,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間唇牧,已是汗流浹背罕扎。 一陣腳步聲響...
    開封第一講書人閱讀 31,991評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留丐重,地道東北人腔召。 一個(gè)月前我還...
    沈念sama閱讀 46,370評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像扮惦,于是被迫代替她去往敵國和親臀蛛。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,527評論 2 349

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