Java基礎:Object類中的equals與hashCode方法

前言java

  這個系列的文章主要用來記錄我在學習和複習Java基礎知識的過程當中遇到的一些有趣好玩的知識點,但願你們也喜歡。程序員

一切皆對象面試

   對於軟件工程來講面向對象編程有一套完整的解決方案:OOA、OOD、OOP,  做爲程序員來說,OOP實際上是直接接觸最多的。Java中OOP最直接的體現就是java.lang.Object了,一切都是對象(除了原生類型,原生類型的 PrimitiveClass對象由JVM啓動時生成和加載),Object類主要就只有這麼幾個方法,其中getClass是反射的基石,notify、notifyAll、wait是多線程併發時經常使用的方法,其中比較有意思的就是hashCode與equals了,也是面試的時候面試官很喜歡問的一個問題。編程

public class Object {

    private static native void registerNatives();
    static {
        registerNatives();
    }

    // finnal的本地方法,子類不能重寫
    public final native Class<?> getClass();
    public final native void notify();
    public final native void notifyAll();
    public final native void wait(long timeout) throws InterruptedException;

    // 本地方法wait的包裝方法
    public final void wait(long timeout, int nanos) throws InterruptedException {
        if (timeout < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }
        if (nanos < 0 || nanos > 999999) {
            throw new IllegalArgumentException("nanosecond timeout value out of range");
        }
        if (nanos >= 500000 || (nanos != 0 && timeout == 0)) {
            timeout++;
        }
        wait(timeout);
    }
    public final void wait() throws InterruptedException {
        wait(0);
    }

    // 爲何hashCode是本地方法,而equals倒是成員方法呢?
    public native int hashCode();

    public boolean equals(java.lang.Object obj) {
        return (this == obj);
    }

    protected native java.lang.Object clone() throws CloneNotSupportedException;

    public String toString() {
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }

    // 對象成員方法,對象被回收時執行的方法,通常不用來釋放資源,由於GC的時機對程序員來講是不可控的
    protected void finalize() throws Throwable { }

}
View Code

equals與hashCode多線程

  面試題的標準答案是:若是兩個對象ab知足a.equals(b) == true,則它們的散列碼(hash code)應當要相同,反之則不必定。這裏也就引伸出:重寫了類的equals方法以後必定要重寫hashCode方法,這種狀況最多見的是在entity bean中,當bean跟容器類搭配使用時若是重寫了equals而沒重寫hashCode就會引發問題,這裏先來看看HashMap的getEntry方法,循環中就是先判斷兩個對象的hash值(由對象的hashCode計算獲得)是否相等,再判斷兩個對象是否爲同一對象最後才調equals方法來判斷,這樣能夠減小equals方法的調用次數,提高容器的性能,若是你們看看Java容器類的源碼就會發現大神們對hash思想的運用簡直爐火純青(生活中哈希的應用也隨處可見:年月日、時分秒就是對時間流的哈希散列)併發

    final Entry<K,V> getEntry(Object key) {
        int hash = (key == null) ? 0 : hash(key);
        for (Entry<K,V> e = table[indexFor(hash, table.length)]; e != null; e = e.next) {
            Object k;
            if (e.hash == hash &&
                    ((k = e.key) == key || (key != null && key.equals(k))))
                return e;
        }
        return null;
    }

 下面是一張抽象化的對比圖:ide

hashCode通常是一個int值,比較兩個對象的hashCode就是比較兩個int值,Java中對原生類型操做的性能確定要好於對方法的調用,因此咱們纔會在Java容器中看到那麼多對hash的應用。性能

上面這張圖也能夠直觀看出爲何說兩個對象equals爲true的話hashCode就必定相同,反之則不必定。學習

equals方法的四大特性this

  經過equals方法的註解就能清晰看到Java大神們給咱們總結的4大特性了(若是在面試中遇到equasl和hashCode的問題時一遍把四大特性闡述一下會是個小小的加分項):

  一、自反性:本身跟本身比較返回true

  二、對稱性:x.equals(y) == y.equals(x)

  三、傳遞性:x.equals(y) == truey.equals(z) == truex.equals(z) == true

  四、一致性:屢次調用equals返回結果相同

  (null與任何對象比較都應該返回false)

 

相關文章
相關標籤/搜索