JDK1.8源碼閱讀筆記(1)Object類


JDK1.8源碼閱讀筆記(1)Object類

​ Object 類屬於 java.lang 包,此包下的所有類在使⽤時⽆需⼿動導⼊,系統會在程序編譯期間⾃動 導⼊。Object 類是所有類的基類,當⼀個類沒有直接繼承某個類時,默認繼承Object類,也就是說任何 類都直接或間接繼承此類,Object 類中能訪問的⽅法在所有類中都可以調⽤。

Object類源碼:

native關鍵字

​ Java有兩種方法:Java方法和本地方法。Java方法是由Java語言編寫,編譯成字節碼,存儲在class文件中。本地方法是由其他語言(比如C,C++,或者匯編)編寫的,編譯成和處理器相關的機器代碼。本地方法保存在動態連接庫中,格式是各個平台專有的。Java方法是平台無關的,單本地方法卻不是。運行中的Java程序調用本地方法時,虛擬機裝載包含這個本地方法的動態庫,並調用這個方法。本地方法是聯系Java程序和底層主機操作系統的連接方法

​ 被native關鍵字修飾的方法叫做本地方法,簡單地講,一個native方法就是一個java調用非java代碼的接口。一個Native Method是這樣一個java的方法:該方法的實現由非java語言實現,比如C。另外native方法在JVM中運行時數據區也和其它方法不一樣,它有專門的本地方法棧。

Object類源碼

package java.lang;

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 { }
}

Object類中的12個方法

clone

​ clone方法可以完成對象的淺克隆。所謂淺克隆就是說被克隆的對象的各個屬性都是基本類型,而不是引用類型(接口、類、數組),如果存在引用類型的屬性,則需要進行深克隆。要想實現 Address的深克隆,首先讓Address類實現 Cloneable 接口,重寫clone方法

之前的文章中寫過clone方法與深拷貝淺拷貝:Java clone() 方法克隆對象——深拷貝與淺拷貝

  protected native Object clone() throws CloneNotSupportedException;

equals

在引用類型中,"=="是比較兩個引用是否指向堆內存里的同一個地址(同一個對象),而equals是一個普通的方法,該方法返回的結果依賴於自身的實現。要比較兩個對象的內容是否相同,需要重寫該方法。

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

finalize

​ finalize()是Object的protected方法,子類可以覆蓋該方法以實現資源清理工作,GC在回收對象之前調用該方法,當對象變成(GC Roots)不可達時,GC會判斷該對象是否覆蓋了finalize方法,若未覆蓋,則直接將其回收。否則,若對象未執行過finalize方法,將其放入F-Queue隊列,由一低優先級線程執行該隊列中對象的finalize方法。執行finalize方法完畢后,GC會再次判斷該對象是否可達,若不可達,則進行回收,否則,對象“復活”。

protected void finalize() throws Throwable { }

getClass

​ Class是一個實實在在的類,在包 java.lang 下,有一個Class.java文件,它跟我們自己定義的類一樣,是一個實實在在的類,Class對象就是這個Class類的實例。在Java里,所有的類的根源都是Object類,而Class也不例外,它是繼承自Object的一個特殊的類,它內部可以記錄類的成員、接口等信息,也就是在Java里,Class是一個用來表示類的類。

public final native Class<?> getClass();

registerNatives

​ 在Object類中,除了有registerNatives這個本地方法之外,還有hashCode()、clone()等本地方法,而在Class類中有forName()這樣的本地方法等等。也就是說,凡是包含registerNatives()本地方法的類,同時也包含了其他本地方法。所以,顯然,當包含registerNatives()方法的類被加載的時候,注冊的方法就是該類所包含的除了registerNatives()方法以外的所有本地方法。使用native方法的好處:

  • 通過registerNatives方法在類被加載的時候就主動將本地方法鏈接到調用方,比當方法被使用時再由虛擬機來定位和鏈接更方便有效;
  • 如果本地方法在程序運行中更新了,可以通過調用registerNative方法進行更新;
  • Java程序需要調用一個本地應用提供的方法時,因為虛擬機只會檢索本地動態庫,因而虛擬機是無法定位到本地方法實現的,這個時候就只能使用registerNatives()方法進行主動鏈接。

registerNatives是⽤ private 關鍵字聲明的,在類外⾯根本調⽤不了。靜態代碼塊就是⼀個類在初始化過程中必定會執⾏的內容,所以在類加載的時候是會執⾏該⽅法的,通過該⽅法來注冊本地⽅法。

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

hashCode

​ hashCode就是對象的散列碼,是根據對象的某些信息推導出的一個整數值,默認情況下表示是對象的存儲地址。通過散列碼,可以提高檢索的效率,主要用於在散列存儲結構中快速確定對象的存儲地址,如Hashtable、hashMap中。

wait notify notifyAll

這三個方法最終調用的都是jvm級的final native方法

  • 如果對象調用了wait方法就會使持有該對象的線程把該對象的控制權交出去,然后處於等待狀態。
  • 如果對象調用了notify方法就會通知某個正在等待這個對象的控制權的線程可以繼續運行。
  • 如果對象調用了notifyAll方法就會通知所有等待這個對象控制權的線程繼續運行。

其中wait方法有三個over load方法:

  • wait()
  • wait(long)
  • wait(long,int)

wait方法通過參數可以指定等待的時長。如果沒有指定參數,默認一直等待直到被通知。

toString()

​ getClass().getName()是返回對象的全類名(包含包名),Integer.toHexString(hashCode()) 是以16進制⽆符號整數形式返回此哈希碼的字符串表示形式。打印某個對象時,默認是調⽤ toString ⽅法,⽐如 System.out.println(object),等價於System.out.println(object.toString())。

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM