1. 程式人生 > >Object詳解

Object詳解

Object類是所有類的父類(包括陣列),Object類中共有12個方法(除了init和cinit以外)。

一個靜態本地方法registerNatives,在類被載入時執行。
5個方法可以被子類覆蓋(也在vtable中)—hashCode(),equals(Object obj),clone(),toString(),finalize()。

6個final的方法,基本邏輯都是由本地方法實現,getClass(),notify(),notifyAll(),wait(long timeout),wait(long timeout, int nanos),wait()


registerNatives方法,作用是通過類載入器,載入一些本地方法到jvm中。
Object類在被載入時,會載入下面的methods中的那些本地方法到jvm中。

static JNINativeMethod methods[] = {
{“hashCode”, “()I”, (void *)&JVM_IHashCode},
{“wait”, “(J)V”, (void *)&JVM_MonitorWait},
{“notify”, “()V”, (void *)&JVM_MonitorNotify},
{“notifyAll”, “()V”, (void *)&JVM_MonitorNotifyAll},
{“clone”, “()Ljava/lang/Object;”, (void *)&JVM_Clone},
};

public final native Class<?> getClass();

這個方法返回的是類的Class物件,具體值取決於呼叫這個方法的物件。關於Class物件在jvm中的作用,在Java虛擬機器第十篇有描述


public native int hashCode();

返回一個物件的雜湊值,主要服務於HashMap的hash tables。

hash值需要遵守的約定:
  • 一致性(consistent),在程式的一次執行過程中,對同一個物件必須一致地返回同一個整數。
  • 如果兩個物件通過equals(Object)比較,結果相等,那麼對這兩個物件分別呼叫hashCode方法應該產生相同的整數結果。
  • 如果兩個物件通過java.lang.Object.equals(java.lang.Ojbect)比較,結果不相等,不必保證對這兩個物件分別呼叫hashCode也返回兩個不相同的整數。雖然如此,但是如果2個物件不相等,那麼返回不同的雜湊值有助於雜湊表的儲存。典型實現是把一個物件的地址轉換成整數。

public boolean equals(Object obj)

判斷2個物件是否相等,預設實現是判斷引用是否相等。
一般來說,如果覆蓋了equals方法,那麼需要覆蓋hashcode方法,用於維持相等物件必須有相等的hashcode這一約束。


protected native Object clone() throws CloneNotSupportedException;

建立並返回這個物件的副本,根據約定,這個方法應該呼叫super.clone()。

根據約定,拷貝的物件應該是獨立於當前物件的(也就是說當前物件的修改,不應該影響到拷貝的物件),對於複雜的結構,需要對內部引用的物件也拷貝一次。也就是說預設實現是淺拷貝的,深拷貝需要自己做處理。比如有一個hashMap,則需要先把hashMap複製一個,再把裡面的內容都複製一遍。

如果想呼叫clone方法,需要這個類實現Cloneable介面,否則丟擲java.lang.CloneNotSupportedException異常。
所有的陣列預設實現了 Cloneable介面。


public String toString()

推薦所有的子類都覆蓋這個方法,預設實現返回類名和物件雜湊值的十六進位制。


public final native void notify();

喚醒等待在這個物件的監視器上的一個執行緒,如果很多執行緒在等待,那麼其中一個會被喚醒,具體哪個執行緒被喚醒取決於具體實現。
(一個執行緒呼叫某個物件的wait方法後,會在這個物件的監視器上等待。)
一個物件應該先持有這個物件的監視器(執行物件的同步方法或者同步塊;對於Class物件,執行靜態同步方法),然後才能呼叫這個方法。

如果當前執行緒沒有持有指定物件的鎖,卻呼叫了notify方法,會丟擲IllegalMonitorStateException異常。


public final native void wait(long timeout) throws InterruptedException;

當前執行緒阻塞指定時間,直到時間到了,或者被其它執行緒notify。這個方法會釋放它持有的所有的鎖。
wait(0)的話,就會一直wait,直到被notify。
呼叫這個方法的前提是當前執行緒必須持有這個物件的minotor。


protected void finalize() throws Throwable { }

當這個物件不再被引用時由垃圾回收器呼叫,子類覆蓋這個方法用於釋放系統資源。
在第一次垃圾回收發現不可達時,會先把finalize方法加到F-Q佇列中由專門的執行緒執行,可以在這個方法中自救。如果沒有自救或者自救失敗,這個類就會被標記為可回收的,再下次垃圾回收時如果還是不可達,並且finalize執行過之後,就會真正的回收。
如果finalize方法發生異常,那麼方法會終止,但是異常會被忽略。


public class Object {

    private static native void registerNatives();
    static {
        registerNatives();
    }
    public final native Class<?> getClass();
    public native int hashCode();
    
    public boolean equals(Object obj) {
        return (this == obj);
    }
    
    protected native Object clone() throws CloneNotSupportedException;

    public String toString() {
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }
    public final native void notify();
    public final native void notifyAll();
    public final native void wait(long timeout) throws InterruptedException;
    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 > 0) {
            timeout++;
        }

        wait(timeout);
    }
     public final void wait() throws InterruptedException {
        wait(0);
    }
    protected void finalize() throws Throwable { }