你真的了解Object源碼嗎


歡迎點贊閱讀,一同學習交流,有疑問請留言 。
GitHub上也有開源 JavaHouse 歡迎star

引入

Object 應該是比較簡單的源碼了。現在我們來分析一下他。Object 是類層次結構的根。Java體系里面的每個類默認都有一個超類就是 Object。總之,所有對象,包含數組,都默認實現該類的方法。

native 關鍵字

因為 Object 類里面有很多地方都用到 native 關鍵字。我們先了解一下這家伙。native 關鍵字是 JNI(Java Native Interface)的重要體現。什么是 JNI ,JNI 是Java調用其他語言(c,c++) 的一種機制。native 關鍵字修飾的是方法,起聲明作用,告訴 JVM 老哥自己去調用這個方法。 這個方法的實現在別的語言那里已經實現,我們是看不到源碼的。

初始化

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

源碼里面一個靜態塊,一個靜態方法和一個沒有顯示的默認構造方法,沒有成員變量。可以看出來 registerNatives() 方法只會被調用一次。

getClass() 方法

public final native Class<?> getClass();

getClass()方法被native修飾,告訴 JVM 自己去調用。同時被 final 修飾,所以不能被子類重寫。主要作用是返回正在運行的類別(Class)。

hashCode() 方法

public native int hashCode();

getClass()方法被native修飾,告訴 JVM 自己去調用,可以被重寫。同時被 final 修飾,所以不能被子類重寫。該方法主要是返回對象的hashcode,主要是為了一些哈希表的數據結構服務的,比如 HashMap 。

在 Java 中hancode 與 對象是否相等密切相關。 如果兩個對象相等,則 hashcode 一定相等,但是 hashcode 相等,兩個對象不一定相等。如果 hashcode 不相等,那么這兩個對象一定不相等。

equals(Object obj)

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

該方法可以被重寫,主要用來判斷兩個對象是否相等。

該方法有一些約定。

  1. 對象任意一個非空對象x, x.equals(x) 返回 true。
  2. 對象任意兩個非空對象 x,y,如果 x.equals(y) 返回true,那么 y.equals(x) 也會返回true, 具有對稱性。
  3. 對象任意三個非空對象 x,y,z,如果 x.equals(y) 返回true, y.equals(z) 返回true, 那么x.equals(z) 返回true, 具有傳遞性。
  4. 對象任意兩個非空對象 x,y,在什么發生變化的情況寫,x.equals(y) 返回總是 true 或者 flase,具有一直性。
  5. 對象任意一個非空對象x, x.equals(null) 返回 false。

Object#equals(Object obj)方法,比較的是內存地址,通常實際應用中我們想比較的是兩個對象里面的屬性內容是否相等,所以會重寫該方法。這里要注意重寫 equals(Object obj) 的時候,也要重寫 hashCode() 方法。 因為 Java 規定:如果兩個對象相等,那么他們的 hashcode 也要相等。舉個 Integer 的例子:

@Override
public boolean equals(Object obj) {
    if (obj instanceof Integer) {
        return value == ((Integer)obj).intValue();
    }
    return false;
}

@Override
public int hashCode() {
    return Integer.hashCode(value);
}

public static int hashCode(int value) {
    return value;
}

clone()

protected native Object clone() throws CloneNotSupportedException;

該方法被native修飾,告訴 JVM 自己去調用。當我們在自定義類中使用該方法的時候,需要繼承一個 Cloneable 接口,否則會拋出無法克隆的異常。該方法是一個淺復制,不是深復制。

淺拷貝:對基本數據類型進行值傳遞,對引用數據類型進行引用傳遞般的拷貝,此為淺拷貝。
深拷貝:對基本數據類型進行值傳遞,對引用數據類型,創建一個新的對象,並復制其內容,此為深拷貝。

  • 使用代碼
@Data
public class Person extends Man implements Cloneable {
    private String name;
    private Person person;

    public static void main(String[] args) throws CloneNotSupportedException {
        Person person = new Person();
        person.setName("chen");
        Person clone = (Person)person.clone();
        System.out.println(clone.toString());
        System.out.println("person.equals(clone):"+person.equals(clone));
        System.out.println("person == clone:"+(person == clone));
        System.out.println("person.person == clone.person:"+(person.person == clone.person));
    }
  • 結果
Person(name=chen, person=null)
person.equals(clone):true
person == clone:false
person.person == clone.person:true

notify()、notifyAll() 和 wait()

public final native void notify();
public final native void notifyAll();
public final void wait() throws InterruptedException {
        wait(0);
    }

notify() 隨機喚醒一個等待線程,notifyAll() 喚醒全部的等待線程。wait() 方法讓當前線程進入等待狀態。

流程圖

無論當前線程調用哪個方法,都有一個前提:當前線程擁有對象的監視器。實現方法也很簡單,配合 synchronized 關鍵字使用。

  • 實現方法
synchronized (obj) {
    while (true)
        obj.wait();
        // obj.notify();          
}

舉一個實際的例子

  • 多線程打印奇偶數
public static void main(String[] args) {
        Thread thread = new Thread(() -> {
        for ( int i = 0; i < 100; i += 2) {
            synchronized (a) {
                System.out.println(Thread.currentThread().getName()+":"+i);
                try {
                    a.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        });
        Thread thread1 = new Thread(() -> {
            for (int i = 1; i < 100; i += 2) {
                synchronized (a) {
                    System.out.println(Thread.currentThread().getName()+":"+i);
                    a.notify();
                }
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        thread.start();thread1.start();
    }

finalize()

protected void finalize() throws Throwable { }

當垃圾回收器確定不再有對該對象的引用時,由垃圾回收器在對象上調用該方法。該方法只會被調用一次。

參考

如果我的文章幫助到您,可以關注我的微信公眾號,第一時間分享文章給您
公眾號.jpg


免責聲明!

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



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