1. 程式人生 > >jdk原始碼分析(1)java.lang.Object

jdk原始碼分析(1)java.lang.Object

java.lang.Object原始碼分析

public final native Class<?> getClass()

官方文件解釋

返回此 Object 的執行時類。返回的 Class 物件是由所表示類的 static synchronized 方法 鎖定的物件。

結論

返回class物件與該類是一對一關係

這裡引入物件鎖和類鎖的概念:

當synchronized修飾一個static方法時,多執行緒下,獲取的是類鎖(即Class本身,注意:不是例項),作用範圍是整個靜態方法,作用的物件是這個類的所有物件。當synchronized修飾一個非static方法時,多執行緒下,獲取的是物件鎖(即類的例項物件), 作用範圍是整個方法,作用物件 是呼叫該方法的物件

class物件詳解後續會在java.lang.Class原始碼分析中詳細分析

public native int hashCode();

官方文件解釋

返回該物件的雜湊碼值。支援此方法是為了提高雜湊表(例如 java.util.Hashtable 提供的雜湊表)的效能。
hashCode 的常規協定是:
在 Java 應用程式執行期間,在對同一物件多次呼叫 hashCode 方法時,必須一致地返回相同的整數,前提是將物件進行 equals 比較時所用的資訊沒有被修改。從某一應用程式的一次執行到同一應用程式的另一次執行,該整數無需保持一致。
如果根據 equals(Object) 方法,兩個物件是相等的,那麼對這兩個物件中的每個物件呼叫 hashCode 方法都必須生成相同的整數結果。
如果根據 equals(java.lang.Object) 方法,兩個物件不相等,那麼對這兩個物件中的任一物件上呼叫 hashCode 方法不 要求一定生成不同的整數結果。但是,程式設計師應該意識到,為不相等的物件生成不同整數結果可以提高雜湊表的效能。
實際上,由 Object 類定義的 hashCode 方法確實會針對不同的物件返回不同的整數。(這一般是通過將該物件的內部地址轉換成一個整數來實現的,但是 JavaTM 程式語言不需要這種實現技巧。)

結論

1.hashcode值不一定是物件地址
2.hashcode主要配合HashSet、HashMap以及HashTable等等使用
3.hashcode相等不代表兩物件相等,但是hashcode不相等代表物件不等

public boolean equals(Object obj)

原始碼

public boolean equals(Object obj) {
	//預設是物件地址是否相等
        return (this == obj); 
}

官方文件解釋

指示其他某個物件是否與此物件“相等”。
equals 方法在非空物件引用上實現相等關係:
自反性:對於任何非空引用值 x,x.equals(x) 都應返回 true。
對稱性:對於任何非空引用值 x 和 y,當且僅當 y.equals(x) 返回 true 時,x.equals(y) 才應返回 true。
傳遞性:對於任何非空引用值 x、y 和 z,如果 x.equals(y) 返回 true,並且 y.equals(z) 返回 true,那麼 x.equals(z) 應返回 true。
一致性:對於任何非空引用值 x 和 y,多次呼叫 x.equals(y) 始終返回 true 或始終返回 false,前提是物件上 equals 比較中所用的資訊沒有被修改。
對於任何非空引用值 x,x.equals(null) 都應返回 false。

hashCode() 和 equals()

為什麼在重寫equals方法的同時,必須重寫hashCode方法

假設People類的equals被重寫,當名字相等是就返回true,執行以下程式碼
HashMap map = new HashMap();
map.put(new People(“tom”), 1);
int i = map.get(new People(“tom”));
預期得到的是1,但是實際得到null,因為hashmap通過hashcode定位Entry陣列的下標,equals查詢該連結串列是否有相等的值,由於沒重寫hashcode方法,導致前後兩次定位Entry陣列下標不一致,導致返回空。

protected native Object clone()

官方文件解釋

建立並返回此物件的一個副本。“副本”的準確含義可能依賴於物件的類。這樣做的目的是,對於任何物件 x,表示式:
x.clone() != x
為 true,表示式:
x.clone().getClass() == x.getClass()
也為true。
按照慣例,此方法返回的物件應該獨立於該物件(正被複制的物件)。要獲得此獨立性,在 super.clone 返回物件之前,有必要對該物件的一個或多個欄位進行修改。這通常意味著要複製包含正在被複制物件的內部“深層結構”的所有可變物件,並使用對副本的引用替換對這些物件的引用。如果一個類只包含基本欄位或對不變物件的引用,那麼通常不需要修改 super.clone 返回的物件中的欄位。

結論

clone方法是淺拷貝,只拷貝除static以外的基本型別,而引用型別是公用的

如何實現深拷貝

1.只需要為物件圖的每一層的每一個物件都實現Cloneable介面並重寫clone方法,最後在最頂層的類的重寫的clone方法中呼叫所有的clone方法即可實現深拷貝。簡單的說就是:每一層的每個物件都進行淺拷貝=深拷貝。
2.將物件序列化為位元組序列後,預設會將該物件的整個物件圖進行序列化,再通過反序列即可完美地實現深拷貝。

public String toString()

原始碼

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

官方文件解釋

Object 類的 toString 方法返回一個字串,該字串由類名(物件是該類的一個例項)、at 標記符“@”和此物件雜湊碼的無符號十六進位制表示組成。

public final native void wait(long timeout)

官方文件解釋

在其他執行緒呼叫此物件的 notify() 方法或 notifyAll() 方法,或者超過指定的時間量前,導致當前執行緒等待。
當前執行緒必須擁有此物件監視器。
此方法導致當前執行緒(稱之為 T)將其自身放置在物件的等待集中,然後放棄此物件上的所有同步要求。出於執行緒排程目的,在發生以下四種情況之一前,執行緒 T 被禁用,且處於休眠狀態:
1.其他某個執行緒呼叫此物件的 notify 方法,並且執行緒 T 碰巧被任選為被喚醒的執行緒。
2.其他某個執行緒呼叫此物件的 notifyAll 方法。
3.其他某個執行緒中斷執行緒 T。
4.大約已經到達指定的實際時間。但是,如果 timeout 為零,則不考慮實際時間,在獲得通知前該執行緒將一直等待。
然後,從物件的等待集中刪除執行緒 T,並重新進行執行緒排程。然後,該執行緒以常規方式與其他執行緒競爭,以獲得在該物件上同步的權利;一旦獲得對該物件的控制權,該物件上的所有其同步宣告都將被恢復到以前的狀態,這就是呼叫 wait 方法時的情況。然後,執行緒 T 從 wait 方法的呼叫中返回。所以,從 wait 方法返回時,該物件和執行緒 T 的同步狀態與呼叫 wait 方法時的情況完全相同。

public final native void notify()

官方文件解釋

喚醒在此物件監視器上等待的單個執行緒。如果所有執行緒都在此物件上等待,則會選擇喚醒其中一個執行緒。選擇是任意性的,並在對實現做出決定時發生。執行緒通過呼叫其中一個 wait 方法,在物件的監視器上等待。
直到當前執行緒放棄此物件上的鎖定,才能繼續執行被喚醒的執行緒。被喚醒的執行緒將以常規方式與在該物件上主動同步的其他所有執行緒進行競爭;例如,喚醒的執行緒在作為鎖定此物件的下一個執行緒方面沒有可靠的特權或劣勢。
此方法只應由作為此物件監視器的所有者的執行緒來呼叫。通過以下三種方法之一,執行緒可以成為此物件監視器的所有者:
1.通過執行此物件的同步例項方法。
2.通過執行在此物件上進行同步的 synchronized 語句的正文。
3.對於 Class 型別的物件,可以通過執行該類的同步靜態方法。(說明了類鎖和物件鎖無關聯)
一次只能有一個執行緒擁有物件的監視器。

protected void finalize()

原始碼

protected void finalize() throws Throwable { }

官方文件解釋

當垃圾回收器確定不存在對該物件的更多引用時,由物件的垃圾回收器呼叫此方法。子類重寫 finalize 方法,以配置系統資源或執行其他清除。
finalize 的常規協定是:當 JavaTM 虛擬機器已確定尚未終止的任何執行緒無法再通過任何方法訪問此物件時,將呼叫此方法,除非由於準備終止的其他某個物件或類的終結操作執行了某個操作。finalize 方法可以採取任何操作,其中包括再次使此物件對其他執行緒可用;不過,finalize 的主要目的是在不可撤消地丟棄物件之前執行清除操作。例如,表示輸入/輸出連線的物件的 finalize 方法可執行顯式 I/O 事務,以便在永久丟棄物件之前中斷連線。
Object 類的 finalize 方法執行非特殊性操作;它僅執行一些常規返回。Object 的子類可以重寫此定義。
Java 程式語言不保證哪個執行緒將呼叫某個給定物件的 finalize 方法。但可以保證在呼叫 finalize 時,呼叫 finalize 的執行緒將不會持有任何使用者可見的同步鎖定。如果 finalize 方法丟擲未捕獲的異常,那麼該異常將被忽略,並且該物件的終結操作將終止。
在啟用某個物件的 finalize 方法後,將不會執行進一步操作,直到 Java 虛擬機器再次確定尚未終止的任何執行緒無法再通過任何方法訪問此物件,其中包括由準備終止的其他物件或類執行的可能操作,在執行該操作時,物件可能被丟棄。
對於任何給定物件,Java 虛擬機器最多隻呼叫一次 finalize 方法。

結論

在該物件將要被回收時呼叫,一般是處理非java資源