今天我們一起來看下Object類的源碼,為什么先看Object類呢,所有的java程序員都知道,Object類是所有其它類的父類,從繼承的層次來看它就是最頂層根,所以它也是java中唯一 一個(gè)沒有父類的類??戳薕bjec類中的方法后就知道,這里面的方法在任何一個(gè)java類中都可以使用。
在看Object類之前先了解下本類中用到的一些java中共用的概念:
1.一個(gè)類被加載的時(shí)候會(huì)先執(zhí)行靜態(tài)代碼塊中的內(nèi)容,也就是static{}主的內(nèi)容,靜態(tài)只能調(diào)用靜態(tài)
2.native 修飾方法為本地方法,這些方法不是由java語(yǔ)言編寫,通常由C、C++語(yǔ)言編寫,當(dāng)我們追蹤源碼時(shí)看到有native標(biāo)識(shí)的方法是,在java層面上就到頭了。
3.在java規(guī)范中接口中的方法沒有方法體,抽象類中的方法方法體為空,本地方法方法需要被省略。
4.被final修飾的方法,子類不可重寫該方法
5.protected修飾的方法只能在本類或是子類中調(diào)用
6.方法名稱相同,參數(shù)不同是java多態(tài)的體現(xiàn),如本類中wait方法
registerNatives方法:
private static native void registerNatives();
static {
registerNatives();
}
??registerNatives是一個(gè)本地方法,它被static修飾,而且在靜態(tài)代碼塊中,所以O(shè)bject類加載的時(shí)候會(huì)先執(zhí)行registerNatives方法,registerNatives方法會(huì)進(jìn)行一些跟系統(tǒng)有關(guān)的方法調(diào)用,而這個(gè)方法的實(shí)現(xiàn)就在java.dll中,里面會(huì)根據(jù)不同系統(tǒng)來執(zhí)行不同的底層操作。
getClass方法:
public final native Class<?> getClass();
??getClass方法是一個(gè)本地方法,被final修飾子類不能夠重寫,通過該方法或以獲取類的元數(shù)據(jù)和方法信息。它能夠獲取一個(gè)類的定義信息,然后使用反射去訪問類的全部信息,包括函數(shù)和字段。
hashCode方法:
public native int hashCode();
??hashCode是一個(gè)本地方法,該方法返回一個(gè)int類型的數(shù)值,對(duì)于包含容器類型的程序設(shè)計(jì)語(yǔ)言來說,基本上都會(huì)涉及到hashCode。在Java中也一樣,hashCode方法的主要作用是為了配合基于散列的集合一起正常運(yùn)行,這樣的散列集合包括HashSet、HashMap以及HashTable等。
equals方法:
public boolean equals(Object obj) {
return (this == obj);
}
??equals是一個(gè)非本地方法,用于比較兩個(gè)對(duì)象是否相等,判斷邏輯也十分簡(jiǎn)單,直接==比較,這里的==比較的是對(duì)象的引用,也就是"地址值",我們自定義對(duì)象的時(shí)候,一般情況下我們需要重寫equals方法(可以看到該方法沒有被final修飾),來使用我們自己的比較邏輯。
比如我們定義一個(gè)People類,我們的判斷邏輯肯定是如果兩個(gè)是的ID相等,那么這兩個(gè)人就是同一個(gè)人。
clone方法;
protected native Object clone() throws CloneNotSupportedException;
??clone是一個(gè)本地方法,被protected修飾,只能在本類或其子類中調(diào)用(當(dāng)然所有的類都是Object的子類,所以在任何類中都可調(diào)用這個(gè)方法),該方法主要實(shí)現(xiàn)對(duì)象的克隆功能,根據(jù)該對(duì)象生成一個(gè)相同的新對(duì)象,我們常見的類的對(duì)象的屬性如果是原始類型則會(huì)克隆值,但如果是對(duì)象則會(huì)克隆對(duì)象的地址。Java的類要實(shí)現(xiàn)克隆則需要實(shí)現(xiàn)Cloneable接口,可以看到該方法會(huì)拋出一個(gè)CloneNotSupportedException異常,如果沒有實(shí)現(xiàn)Cloneable接口而調(diào)用了clone方法,系統(tǒng)就會(huì)拋出這個(gè)異常。
toString方法
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
??toString方法是一個(gè)非本地方法。邏輯是獲取class名稱加上@再加上十六進(jìn)制的hashCode。當(dāng)我們用System.out.println()輸出對(duì)象的時(shí)候?qū)嶋H上會(huì)調(diào)用對(duì)象的toString方法(原因可查看文章最后,本來想添加一個(gè)錨點(diǎn)的,但是簡(jiǎn)書好像不支持,或是誰(shuí)有好的方法可在評(píng)論里告訴我下) ,所以我們?nèi)绻覀兿肟吹阶远x的輸出信息時(shí)可以重寫對(duì)象的toString方法。
notify方法
public final native void notify();
??notify是一個(gè)本地方法,被final修飾,所以不可被重寫,此方法用來喚醒單個(gè)線程(如果不明白的話可以搜一個(gè)java線程相關(guān)的內(nèi)容)。
notifyAll方法:
public final native void notifyAll();
??與notify方法類似,只是notifyAll喚醒的是所有的線程。
wait(long timeout)方法:
public final native void wait(long timeout) throws InterruptedException;
??wait是一個(gè)本地方法,被final修飾,wait方法的作用是讓線程等待,指定的時(shí)長(zhǎng)(timeout單位是毫秒,如果時(shí)長(zhǎng)為0那么休眠時(shí)間將不再生效),即讓當(dāng)前線程等待,直到調(diào)用了notify或是notifyAll方法或是指定的時(shí)長(zhǎng)已經(jīng)過去。該方法可以拋出中斷異常。
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);
}
??該方法本質(zhì)上還是調(diào)用了wait(timeout)方法,只不過是更好的控制了時(shí)間,nanos為納秒, 1毫秒 = 1000 微秒 = 1000 000 納秒,如果超出時(shí)間限制timeout小于0,或是超出了nanos的范圍則會(huì)拋出異常,如果nanos大于0,則等待時(shí)間會(huì)增加1毫秒。
wait方法:
public final void wait() throws InterruptedException {
wait(0);
}
??此方法實(shí)際上調(diào)用的是wait(int timeout)方法只不過timeout傳的是0,這就意味著休眠時(shí)間有再生效,只有調(diào)用了notify或是notifyAll方法,線程才會(huì)被喚醒。
finalize方法:
protected void finalize() throws Throwable { }
??java的垃圾回收機(jī)制大家想必都了解過一點(diǎn),這個(gè)方法用于當(dāng)對(duì)象被回收時(shí)調(diào)用,Object的finalize方法默認(rèn)是什么都沒有做,如果子類需要在對(duì)象被回收時(shí)執(zhí)行一些邏輯處理,則可以重寫finalize方法。
至此java的Object類大家都看明白了,等等,還有一點(diǎn),getClass、hashCode、equals、clone、toString、finalize這些方法放在Object中都很好理解,wait、notify、notifyAll這些方法是用來操作線程為什么定義在Object類中。因?yàn)檫@些方法是配合java的synchronized鎖來一起使用的,而鎖的對(duì)象是任意的,既然被鎖的對(duì)象是任意的,就意味著任意對(duì)象都可以調(diào)用這些方法,那么這些方法當(dāng)然應(yīng)該被定義在Object類中了。看來java的創(chuàng)造者考慮的還是挺全面的。
為什么說System.out.println()輸出對(duì)象的時(shí)候會(huì)調(diào)用對(duì)象的toString方法:
??在System類中我們可以看到有一個(gè)out屬性,類型是PrintStream:
public final static PrintStream out = null;
??再看PrintStream的println方法,會(huì)調(diào)用String.valueOf方法將對(duì)象轉(zhuǎn)換為String類型:
public void println(Object x) {
String s = String.valueOf(x);
synchronized (this) {
print(s);
newLine();
}
}
??而在String類的valueOf方法中:
public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString();
}
??如果對(duì)象不是null的話,返回的是對(duì)象的toString()方法。
??所以System.out.println()輸出對(duì)象的時(shí)候會(huì)調(diào)用對(duì)象的toString方法