java.lang.Object原始碼分析
一、Object類
Object類是Java中所有類的基類,在編譯時會自動匯入,位於java.lang包中,而Object中具有的屬性和行為,是Java語言設計背後的思維體現。這裡寫的程式碼是JDK8中的,其他版本的JDK可能略有不同。
二、Object構造方法
Object類中沒有顯示的提供構造方法,這是編譯器預設提供的。
三、Object類方法
Object類中的大部分方法都是native方法,用此關鍵字修飾的方法是Java中的本地方法,一般是用C/C++語言來實現。
private static native void registerNatives()
其主要作用是將C/C++中的方法對映到Java中的native方法,實現方法命名的解耦。函式的執行是在靜態程式碼塊中執行的,在類首次進行載入的時候執行。
private static native void registerNatives(); /*物件初始化時自動呼叫此方法*/ static { registerNatives(); }
public final native Class<?> getClass();
物件初始化時自動呼叫此方法
public native int hashCode();
返回物件的雜湊碼,是一個整數。這個方法遵守以下三個規則:
1. 在java程式執行期間,若用於equals方法的資訊或者資料沒有修改,name同一個物件多次呼叫此方法,返回的雜湊碼是相同的。而在兩次獨立的執行java程式時,對於同一物件,不需要返回的雜湊碼相同
2. 如果根據equals方法,兩個物件相同,則這兩個物件的雜湊碼一定相同
3. 假如兩個物件通過equals方法比較不相同,那麼這兩個物件呼叫hashCode也不是要一定不同,相同也是可以的。但是使用者應該知道對不同的物件產生不同的hashCode是可以提高hash tables的效能的。在實際使用中,要儘量保證對於不同的物件產生不同的雜湊碼。hashCode的典型實現是將物件的內部地址轉為一個整數,但是這種實現技術不是Java語言必須要採用的。
public boolean equals(Object obj)
equals方法主要是比較兩個物件是否相同,Object中的equals方法比較的是物件的地址是否相同。在我們實際的程式設計過程中,如果要是將一個類作為hashMap等型別的鍵值時,則此類是需要實現equals和hashCode方法,主要是用來比較鍵值是否相等以及進行雜湊化。
public boolean equals(Object obj) { return (this == obj); }
protected native Object clone()
clone方法是建立並且返回一個物件的複製之後的結果。複製的含義取決於物件的類定義。這個方法一般的意圖是對於物件x,能夠保證以下的表示式成立:
1. x.clone() != x; 2. x.clone().getClass() == x.getClass(); 3. x.clone().equals(x);
這些表示式一般都為true,但是並不是絕對需要的。
按照慣例,返回的物件應該通過呼叫super.clone()來取得。如果一個類以及它所有的超類都服從這個慣例,那麼x.clone().getClass()==x.getClass()成立。
按照慣例,clone方法返回的物件是獨立於呼叫clone方法的物件。為了獲得這種獨立性,在返回克隆物件之前,需要修改物件的成員變數。即如果我們要是複製可變的物件,內部的部分成員變數是由指定可變物件的引用組成,那麼我們對這些成員變數也要進行clone複製,下面有例子說明。但是如果需要複製的類的成員變數是由基本型別或者由指向不可變物件的引用組成,那麼我們不需要任何修改,直接對物件呼叫clone方法即可。
如果一個類沒有實現Cloneable介面(這個接口裡面沒有任何方法的宣告,是一個標記介面),那麼對此類的物件進行復制時,在執行時會出現CloneNotSupportedException異常。protected native Object clone() throws CloneNotSupportedException;
更深入的學習關於深克隆及淺克隆的知識請轉閱博主另一篇博文深入理解深克隆與淺克隆
public String toString()
可以看到Object中toString方法的實現是返回類的名稱(許可權定名稱)加上@,然後 加上此類的雜湊碼的16進製表示,例如:[email protected]
public String toString(){ return getClass().getName() + "@" + Integer.toHexString(hashCode()); }
public final native void notity();
通知可能等待該物件的物件鎖的其他執行緒。由JVM(與優先順序無關)隨機挑選一個處於wait狀態的執行緒。
- 在呼叫notify()之前,執行緒必須獲得該物件的物件級別鎖
- 執行完notify()方法後,不會馬上釋放鎖,要直到退出synchronized程式碼塊,當前執行緒才會釋放鎖
- notify()一次只隨機通知一個執行緒進行喚醒public final native void notifyAll();
和notify()差不多,只不過是使所有正在等待池中等待同一共享資源的全部執行緒從等待狀態退出,進入可執行狀態
讓它們競爭物件的鎖,只有獲得鎖的執行緒才能進入就緒狀態
每個鎖物件有兩個佇列:就緒佇列和阻塞佇列
- 就緒佇列:儲存將要獲得鎖的執行緒
- 阻塞佇列:儲存被阻塞的執行緒
public final void wait()
在Object中存在三種wait方法,可見wait()和wait(long timeout, int nanos)都在在內部呼叫了wait(long timeout)方法。
在其他執行緒呼叫此物件的notify()方法或notifyAll()方法前,導致當前執行緒等待。換句話說,此方法的行為就好像它僅執行wait(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); }
更深入的學習關於wait()方法的知識請轉閱博主另一篇博文wait()和notify()深入剖析