Object類介紹
Object類作為java所有類中的超類,看似很牛,(๑╹ヮ╹๑)好吧,其實確實很牛,畢竟他是所有類的祖先,是java繼承體系中真正的根節點,其實我們在學習的過程中慢慢的就會發現,越是底層的類,其功能就越復雜,而越處於上層,其功能反而越簡單,但Object真的是這樣嗎?其實簡單僅僅是類內部的方法少,並不是容易學,其反而更加抽象,更加難以理解
Object類是java.lang包下的,java.lang包下的類不需要導入就可以直接使用,因為java只有單繼承和多重繼承,即每一個類只能有一個父類,但其父親卻同樣可以擁有父親,以此類推即為多重繼承。所以對於Object中聲明的方法,在我們所見到的類(包括我們自己寫的)都具有這些方法,我們一般不會直接使用Object的對象,而是重寫繼承自Object類的方法,
/* * Object類是類層次結構的根。每個類都有 Object作為超類。所有對象,包括數組,實現這個類的方法。 */ public class Object { /* native: * 我們看到了有好幾個方法是由native修飾的,那么native方法是什么意思呢? * native關鍵字說明其修飾的方法是一個原生態方法,方法對應的實現不是在當前文件,而是在用其他語言(如C和C++)實現的文件中。 * Java語言本身不能對操作系統底層進行訪問和操作,但是可以通過JNI(Java Native Interface)接口調用其他語言來實現對底層的訪問。 * JNI是Java本機接口,是一個本機編程接口,它是JDK的一部分。JNI允許Java代碼使用以其他語言編寫的代碼和代碼庫。 * InvocationAPI(JNI的一部分)可以用來將Java虛擬機(JVM)嵌入到本機應用程序中,從而允許程序員從本機代碼內部調用Java代碼。 */ private static native void registerNatives(); /* * registerNatives(): * 顧名思義,在類初始化時調用registerNatives()方法進行本地方法的注冊,也就是初始化java原生方法(native修飾)映射到對應的其他語言描述方法,比如c語言的方法 * 我們可以發現用native修飾的方法都沒有具體的方法體(類似於抽象方法),因為不需要java來實現,是使用其他語言實現的。直接調用即可,而且同時用final修飾,我們都無法重寫 * 但是hashCode()卻不一樣,並沒有final修飾,而hashCode()的重寫對於散列數據結構大有用處。所以說hashCode()既是一個native方法也是一個java方法。 */ static { registerNatives(); } /* * getClass(): * getclass()方法返回該 Object運行時類,一般在反射時,我們想得到某個類的class對象,可以通過對象.getClass()獲得,但幾乎不常用,因為既然都有對象了就不用反射了。 */ public final native Class<?> getClass(); /* * hashCode(): * 學習hashCode(),需要先學習equals(Object obj),hashCode()一般不單獨使用,hashCode()的功能是在比較倆個對象是否相等的時候提高比較效率,比如在一些hashSet、hashTable等 * 數據結構中,不允許存在相同的元素,所以每次插入元素都要和已經存在的元素依次進行比較,如果依次對每個元素調用equals(Object obj),對於大量數據來說太慢了,hashCode()便是在哈希表 * 結構中提高比較速率的利器,如果倆個元素的hashCode()不同,則equals(Object obj)就不必比較了,因為肯定不同;如果倆個元素的hashCode()相同,則再比較equals(Object obj) * 於是我們得出了一個結論:hashCode()相同,equals(Object obj)不一定相同;hashCode()不同,equals(Object obj)一定不同;equals(Object obj)相同,hashCode()一點相同; * 但是有一個前提,必須同時重寫equals(Object obj)和hashCode()。 */ public native int hashCode(); /* * equals(Object obj): * equals(Object obj)方法是比較倆個對象是否相等的主要方法,通過源碼我們可以看出如果某個類不重寫equals(Object obj)方法,那么equals(Object obj)就是==, * 而==比較的是基本類型的內容,引用類型的地址,其實無論基本類型還是引用類型,==比較的都是棧內存中的值,可以去看一下JVM的內存模型就明白了。言歸正傳,不重寫equals(Object obj)的話 * 和==的功能一樣,我們可以通過系統的模板一鍵重寫,重寫默認比較的是所有屬性的值,也可以根據自己的實際需求,去改寫自己需要的功能。 * String類默認重寫了此方法。 */ public boolean equals(Object obj) { return (this == obj); } /* * 返回一個此類的克隆對象,二者具有相同的屬性,二者擁有獨立的屬性存儲空間,分別位於堆內存中的倆快空間中,不相互影響,但是也不是絕對的,因為存在淺克隆和深克隆的區別,我會用一篇文章來介紹深克隆和淺克隆 * 這里注意區別a = b 和 a = b.clone(),他們在堆內存中的存儲不一樣。 */ protected native Object clone() throws CloneNotSupportedException; /* * toString(): * 最最最常用的方法,如果你定義一個類,而不去重寫toString()的話,那你每一次想看看該類的某個對象的某些屬性,你就不得不寫一堆getXxx()方法,簡直了。其實在輸出一個字符串對象a時,輸出的就是 * a.toString();我們在類中重寫此方法后,直接輸出就是調用此方法,也就是依次遍歷對象的所有屬性。但是System.out.println(a)和System.out.println(a.toString())是有區別的 * 當a對象沒有實例化時,其中一個會報出NullPointException,至於是哪個,自己動手去試試不就知道了嘛。 */ public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); } /* * notify(): * 接下來的倆個方法(notify()和wait())都是在多線程中使用的,至於為什么多線程的方法要寫在Object中,這就難以琢磨了! * notify()喚醒一個在這個對象的監視器上等待的單個線程。什么是監視器呢,我們知道一個CPU一次只能處理一個進程(線程),那么是誰保證只能有一個進程進入CPU呢, * 別忘了,每個進程都是自私的,他可不管里面有沒有其他同類。所以我們需要一套規則,需要一個上帝來制約所有的進程,監視器就是這個上帝,他負責某些進程,來維護他們之間的秩序。 * 喚醒的線程不是得到CPU的使用權,而是和其他就緒線程競爭。也就是將阻塞狀態轉換為就緒狀態,並不是立即執行。 * */ public final native void notify(); /* * notifyAll(): * notifyAll()喚醒一個在這個對象的監視器上等待的所有線程,只要記住喚醒的線程不是得到CPU的使用權,而是和其他就緒線程競爭。 */ public final native void notifyAll(); /* * wait(long timeout): * wait(long timeout)使當前線程等待另一個線程調用此對象的方法或 notify() notifyAll()方法,或一個指定的時間流逝,API上的谷歌翻譯,有點拗口,其實我也不明白什么意思 * 我猜測大致是,wait方法是一個線程進行等待狀態,等待多長時間有參數決定,時間到后自動喚醒,或者在等待期間又其他進程調用其的notify或者notifyAll方法進行喚醒。 * 而wait(0)代表無限期的等待。因為等待0秒毫無意義! * 通過下面的源碼,我們可以很明確的看出:wait()==wait(0)==wait(0,0)都是無限期的等待,直到被notify() notifyAll()喚醒 */ public final native void wait(long timeout) throws InterruptedException; /* * */ 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); } /* * */ public final void wait() throws InterruptedException { wait(0); } /* * finalize(): * 當垃圾收集確定沒有對對象的引用時,由對象上的垃圾收集器調用。子類重寫 finalize方法配置系統資源或執行其他清理。垃圾回收機制中的方法,我會用一章來詳細講解垃圾回收機制 */ protected void finalize() throws Throwable { } }