天天看點

JDK1.8源碼閱讀記錄lang包object類JDK1.8源碼閱讀記錄

JDK1.8源碼閱讀記錄

JAVA.LANG包

Object類

registerNatives()

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

native關鍵字說明該方法是原生函數,即該方法是基于C/C++實作的,并被編譯成了DLL,由Java調用,驗證了Java是由C/C++編寫出來的語言。實際上Java就是在不同的平台上調用不同的native方法實作對作業系統的通路的,是以Java具有跨平台的特性。

static說明該方法是靜态方法,可以由 類.方法名() 進行調用。

native是調用本地實作方法,registerNatives則是對本地方法注冊,裝載本地庫。在Object初始化時執行。

getClass()

public class SecondClass extends FirstClass {
    public SecondClass() {
    }
}
           

2.主函數

public class Main {
    public static void main(String[] args) {
        FirstClass firstClass1=new SecondClass();
        FirstClass firstClass2=new FirstClass();
        System.out.println(firstClass1.getClass());
        System.out.println(firstClass2.getClass());
        System.out.println(FirstClass.class);
    }
}
           

3.輸出結果

JDK1.8源碼閱讀記錄lang包object類JDK1.8源碼閱讀記錄

結論:

對象.getClass() 方法傳回的結果與 類.class屬性一樣的。

若有繼承關系,通過子類構造父類的對象,該對象的對象.getClass() 方法将傳回子類的類名。

注:該方法的傳回值是class類型,而不是String類型。

hashCode()

傳回對象的哈希碼值。主要是保證基于散列的集合,如HashSet、HashMap以及HashTable等,在插入元素時保證元素不可重複,同時為了提高元素的插入删除便利效率而設計;主要是為了查找的便捷性而存在。

在一次程式運作過程,如果沒有修改一個對象的任何資訊,則在多次調用對象.hashCode()時,傳回的都是相同的整數。如果不是在同一次程式運作過程,則傳回的整數不一定相同。

根據equals(Object)方法判斷出來的兩個對象,如果是相等的話,則其哈希碼值也相同;如果兩個對象不相等的話,則其哈希碼值也不相同。

我們驗證一下,基于剛剛的幾個類,修改下主函數

public class Main {
    public static void main(String[] args) {
        FirstClass firstClass1=new SecondClass();
        FirstClass firstClass2=new FirstClass();
        FirstClass firstClass11=firstClass1;
        System.out.println(firstClass1.equals(firstClass11)+"-"+firstClass1.hashCode()+"-"+firstClass11.hashCode());
        System.out.println(firstClass1.equals(firstClass2)+"-"+firstClass2.hashCode());
    }
}
           

運作後結果:

JDK1.8源碼閱讀記錄lang包object類JDK1.8源碼閱讀記錄

結果跟我們預想的一樣。

equals(Object obj)

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

訓示其他某個對象是否“等于”該對象。

由此方法引出“==”運算符,通常情況下,==運算符用于比較基本類型的值是否相同,而equals用于比較兩個對象是否相同。

在Object中,equals和==是等價的,隻要兩個對象的引用相同,則該結果将是true。

在我們自定義對象的時候,一般要重寫equals方法。以下是網上找的String中重寫的equals方法

public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = value.length;
        if (n == anotherString.value.length) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;
            while (n-- != 0) {
                if (v1[i] != v2[i])
                    return false;
                i++;
            }
            return true;
        }
    }
    return false;
}
           

由于String是引用類型,可能會出現字元串内容相同但引用不相同的情況,是以我們一般比較的是字元串内容是否相等,故在上述方法中,我們先判斷引用是否相同,若相同則字元串内容必相同。否則的話,我們再判斷變量是否是字元串類型,不是的話則必不相同;是的話則再進一步判斷兩個字元串的長度以及各個位置上的字元是否一緻,若都一緻,則判定為兩個對象相同。

該方法具有自反性(除了非空對象,自己跟自己比較必相同)、對稱性(若沒有非空對象,無論誰調用該方法比較另一個對象,結果不變)、傳遞性(x跟y比較true,y跟z比較true,則x跟z比較同樣是true)、一緻性(在不改變對象a跟b的情況下,對象a多次調用該方法比較對象b,結果不變)

注:非空對象調用該方法會抛出異常,是以我們一般建議由非空的對象調用該方法比較未知對象。

clone()

顧名思義,該方法是複制對象的作用,用來建立一個與源對象相同的對象。

使用clone複制一個對象,即配置設定與源對象相同的記憶體,再用源對象對應的各個域,填充到新對象的域中,最後傳回新對象。

同樣,建立對象還有new操作符可以進行。運作new操作符時,根據new操作符後面的類型,配置設定對應的記憶體空間,再調用構造函數,填充新對象的各個域,即初始化。

在上面的例子中,

FirstClass firstClass1=new SecondClass();
FirstClass firstClass2=new FirstClass();
FirstClass firstClass11=firstClass1;
           

通過new,建立對象。每一次new,都會在棧區多一個引用,在堆區多一個對象,該引用指向該對象。

通過= ,在棧區複制了引用,新引用指向了源引用指向的對象,即firstClass11與firstClass1指向相同的對象。前後變化的隻有在棧區多了一個新引用。

而clone方法,也是在棧區多一個引用,在堆區多一個對象,該引用指向該對象。與new不同的是,新對象的内容跟源對象的内容相同。

toString()

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

toString方法,預設傳回的String是類名加上‘@’符号加上16進制無符号整數形式傳回此哈希碼的字元串表示形式。

直接輸出對象和使用toString是一樣的。

public class Main {
    public static void main(String[] args) {
        FirstClass firstClass1=new SecondClass();
        System.out.println(firstClass1.getClass());
        System.out.println(firstClass1+"\n"+firstClass1.toString());
    }
}
           

結果:

JDK1.8源碼閱讀記錄lang包object類JDK1.8源碼閱讀記錄

finalize()

finalize用于垃圾回收,主要由JVM調用。

小結

關于Object類的源碼閱讀先做到這裡,至于還有幾個方法:**notify()/notifyAll()/wait()**等到多線程時我們在來做分析。

finalize()

finalize用于垃圾回收,主要由JVM調用。

小結

關于Object類的源碼閱讀先做到這裡,至于還有幾個方法:**notify()/notifyAll()/wait()**等到多線程時我們在來做分析。

這是本人第一篇部落格,如有錯誤之處,還望指出,感謝閱讀,2020年2月27日 15:43:36,寫這篇部落格花費1個半小時,還望本人再接再厲,更近一層樓!

轉載請注明:【麻辣西瓜zero的部落格】