Object類源碼解析
本文的分析基於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類源碼解析