1. 程式人生 > >Object類源碼解析

Object類源碼解析

() time cte con 重寫 集合 set集合 final 淺拷貝

本文的分析基於JDK 1.8
Java中所有的類都繼承自Object類。

Object類的源碼解析

1.void registerNatives()

   private static native void registerNatives();
    static {
        registerNatives();
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

該方法只是對幾個本地方法進行註冊(即初始化java方法映射到C的方法)。需要註意的是,很多類中都有這個方法,但是執行註冊的目標是不同的。System類中也有該方法,但是它註冊的方法是另一些方法。

2.Class <?> getClass()方法

    public final native Class<?> getClass();
  • 1
  • 1

這也是一個本地方法,返回一個對象的運行時類。註意是運行時類。請看下列代碼:


public class tests
{
    public static void main(String[] args)
    {
        A te = new B();
        System.out.println(te.getClass());
    }
}
class A{

}
class B extends A
{

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

運行結果是:

class B
  • 1
  • 2
  • 1
  • 2

A類的引用,但是運行時te這個對象的實際類是B。

3.int hashCode()方法

public native int hashCode();
  • 1
  • 1

這也是一個本地方法,返回值是對象的一個哈希值。
在編寫實現hashCode()方法時,我們需要遵守一些約定:

  • 在應用程序執行期間,如果一個對象用於equals()方法的屬性沒有被修改的話,那麽要保證對該對象多次返回的hashcode值要相等。
  • 如果2個對象通過equals()方法判斷的結果為true,那麽要保證二者的hashcode值相等。
  • 如果2個對象通過equals()方法判斷的結果為false,那麽對二者hashcode值是否相等並沒有明確要求。如果不相等,那麽能夠提升散列表的性能。

4.boolean equals(Object obj)

    public boolean equals(Object obj) {
        return (this == obj);
    }
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

從這裏我們可以看到,equals(obj)方法最根本的實現就是‘==’,因此對於一些自定義類,如果沒有重寫hashcode()方法和equals()方法的話,利用‘==’和equals()方法比較的結果是一樣的。對於‘==’比較的是地址,equals()方法比較的是內容這種說法,是片面的。(雖然在最常用的String類中是這樣的)。

5.Object clone()

protected native Object clone() throws CloneNotSupportedException;
  • 1
  • 1

這個也是本地方法。需要註意的是該方法是“淺拷貝”的。

  • 淺拷貝:如果一個對象內部還有一個引用類型的基本變量,那麽再拷貝該對象的時候,只是在通過clone方法新產生的新對象中拷貝一個該基本類型的引用。換句話說,也就是新對象和原對象他們內部都含有一個指向同一對象的引用。
  • 深拷貝:拷貝對象的時候,如果對象內部含有一個引用類型類型的變量,那麽就會再將該引用類型的變量指向的對象復制一份,然後引用該新對象。

下面2個圖可以幫助理解:

技術分享

6.String toString()方法

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

很簡單,就是返回信息而已。該方法經常被重寫。

7.final void notify()方法和final void notifyAll()方法

這2個方法都是本地方法,前者喚醒一個當前對象監視器上等待的線程。後者喚醒所有當前對象監視器上等待的線程。
我們應該註意的是,這2個方法應當僅僅被擁有對象監視器的線程所調用。而一個線程成為對象的監視器的擁有者有三種方法:

  • 執行該對象上的一個同步(synchronized)方法
  • 執行一個同步在在對象上的代碼塊
  • 執行該對象的類上的靜態同步方法
    public final native void notify();
    public final native void notifyAll();
  • 1
  • 2
  • 1
  • 2

8.final native void wait()方法

本地方法
首先,調用該方法會拋出中斷異常(InterruptedException),調用時應該用try catch捕捉。

    public final void wait() throws InterruptedException {
        wait(0);//0表示沒有時間限制。
    }
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

9.final native void wait(long timeout)

本地方法
該方法也會拋出中斷異常,調用時應捕捉。

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

該方法使當前線程等待,直到另外一個線程調用該對象的notify或notifyAll方法,或者等待時間已到,當前線程才會從等待池移到運行池。
如果在wait之前或者wait的時候,當前線程被中斷了,那麽直到該線程被恢復的時候才會拋出中斷異常(InterruptedException)。

10.final void wait(long timeout,int nanos)

該方法可能會拋出中斷異常,調用時應捕捉。

    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);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

源碼只是將timeout四舍五入,並沒有提供更高精度的控制。

11.protected void finalize()方法

垃圾回收器在認為該對象是垃圾對象的時候會調用該方法。子類可以通過重寫該方法來達到資源釋放的目的。
在方法調用過程中出現的異常會被忽略且方法調用會被終止。
任何對象的該方法只會被調用一次。

總結

    • 本地方法有:除了equal()、wait()、wait(long timeout,long nanos)和toString()方法其余均是本地方法。
    • equals()方法經常被重寫,而在重寫的時候,hashcode()方法應當也重寫。例如:當用equals()方法判斷對象內容一致的時候,如果hashcode()方法沒有重寫而導致使用該方法得到的哈希值不同,這樣就會產生歧義(比如在Set集合中是通過對象的hashcode值來“辨別”對象的,如果對象內容一致,hashcode值卻不一致,會在使用Set集合操作時產生歧義)。(其實我感覺這應該就是制定編寫hashcode()方法需要遵守那幾個規範的原因)

Object類源碼解析