1. 程式人生 > >深入研究java.lang.Object類

深入研究java.lang.Object類

下一個 line 版本號 gin bool 獲得 不同 ava 表達

前言:Java的類庫日益龐大。所包括的類和接口也不計其數。但當中有一些非常重要的類和接口,是Java類庫中的核心部分。常見的有String、Object、Class、Collection、ClassLoader、System、Runtime...,掌握類是靈活Java這門語言的基礎。而這些類一般都非常好理解和運用,須要做深入的研究和實踐才幹掌握。

一、概述:
Object類是全部Java類的祖先。每一個類都使用 Object 作為超類。

全部對象(包含數組)都實現這個類的方法。
在不明白給出超類的情況下。Java會自己主動把Object作為要定義類的超類。
能夠使用類型為Object的變量指向隨意類型的對象。


Object類有一個默認構造方法pubilc Object(),在構造子類實例時,都會先調用這個默認構造方法。
Object類的變量僅僅能用作各種值的通用持有者。要對他們進行不論什麽專門的操作,都須要知道它們的原始類型並進行類型轉換。

比如:
Object obj = new MyObject();
MyObject x = (MyObject)obj;

二、API預覽
Object()
默認構造方法
clone()
創建並返回此對象的一個副本。
equals(Object obj)
指示某個其它對象是否與此對象“相等”。
finalize()
當垃圾回收器確定不存在對該對象的很多其它引用時,由對象的垃圾回收器調用此方法。
getClass()
返回一個對象的執行時類。
hashCode()
返回該對象的哈希碼值。


notify()
喚醒在此對象監視器上等待的單個線程。
notifyAll()
喚醒在此對象監視器上等待的全部線程。
toString()
返回該對象的字符串表示。


wait()
導致當前的線程等待,直到其它線程調用此對象的 notify() 方法或 notifyAll() 方法。


wait(long timeout)
導致當前的線程等待,直到其它線程調用此對象的 notify() 方法或 notifyAll() 方法。或者超過指定的時間量。
wait(long timeout, int nanos)
導致當前的線程等待。直到其它線程調用此對象的 notify() 方法或 notifyAll() 方法,或者其它某個線程中斷當前線程,或者已超過某個實際時間量。

三、方法使用說明
1、equals()方法:用於測試某個對象是否同還有一個對象相等。它在Object類中的實現是推斷兩個對象是否指向同一塊內存區域。

這中測試用處不大,由於即使內容同樣的對象。內存區域也是不同的。假設想測試對象是否相等。就須要覆蓋此方法。進行更有意義的比較。比如
class Employee{
... //此樣例來自《java核心技術》卷一
public boolean equals(Object otherObj){
//高速測試是否是同一個對象
if(this == otherObj) return true;
//假設顯式參數為null,必須返回false
if(otherObj == null) reutrn false;
//假設類不匹配。就不可能相等
if(getClass() != otherObj.getClass()) return false;

//如今已經知道otherObj是個非空的Employee對象
Employee other = (Employee)otherObj;

//測試全部的字段是否相等
return name.equals(other.name)
&& salary == other.salary
&& hireDay.equals(other.hireDay);
}
}
Java語言規範要求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。

從這裏看出,上面的樣例是Java規範的equals方法的標準實現,推薦用上面樣例的寫法實現類的equals方法。

2、toString():返回該對象的字符串表示。Object類中的toString()方法會打印出類名和對象的內存位置。差點兒每一個類都會覆蓋該方法,以便打印對該對象當前狀態的表示。

大多數(非所有)toString()方法都遵循例如以下格式:類名[字段名=值,字段名=值...]。當然,子類應該定義自己的toString()方法。比如:

public String toString(){
reurn "Employee[name=" + name + ",salary=" + salary + ",hireDay=" + hireDay + "]";
}
toString()方法是非常重要的調試工具,非常多標準類庫中的類都定義了toString()方法。以便程序猿獲得實用的調試信息。


3、clone():創建並返回此對象的一個副本。“副本”的準確含義可能依賴於對象的類。

這樣做的目的是。對於不論什麽對象 x。

表達式: x.clone() != x為 true,表達式: x.clone().getClass() == x.getClass()也為 true,但這些並沒必要要滿足的要求。

普通情況下: x.clone().equals(x)為 true。但這並沒必要要滿足的要求。

4、notify():喚醒在此對象監視器上等待的單個線程。假設全部線程都在此對象上等待,則會選擇喚醒當中一個線程。選擇是隨意性的,並在對實現做出決定時發生。

線程通過調用當中一個 wait 方法,在對象的監視器上等待。


直到當前線程放棄此對象上的鎖定,才幹繼續運行被喚醒的線程。被喚醒的線程將以常規方式與在該對象上主動同步的其它全部線程進行競爭。比如,喚醒的線程在作為鎖定此對象的下一個線程方面沒有可靠的特權或劣勢。

此方法僅僅應由作為此對象監視器的全部者的線程來調用。通過下面三種方法之中的一個,線程能夠成為此對象監視器的全部者:

  • 通過運行此對象的同步實例方法。
  • 通過運行在此對象上進行同步的 synchronized 語句的正文。

  • 對於 Class 類型的對象,能夠通過運行該類的同步靜態方法。

一次僅僅能有一個線程擁有對象的監視器。


5、notifyAll():喚醒在此對象監視器上等待的全部線程。線程通過調用當中一個 wait 方法,在對象的監視器上等待。

直到當前線程放棄此對象上的鎖定。才幹繼續運行被喚醒的線程。

被喚醒的線程將以常規方式與在該對象上主動同步的其它全部線程進行競爭。比如,喚醒的線程在作為鎖定此對象的下一個線程方面沒有可靠的特權或劣勢。


6、wait(long timeout):在其它線程調用此對象的 notify() 方法或 notifyAll() 方法,或者超過指定的時間量前。導致當前線程等待。
當前線程必須擁有此對象監視器。


此方法導致當前線程(稱之為 T)將其自身放置在對象的等待集中,然後放棄此對象上的全部同步要求。

出於線程調度目的,在發生下面四種情況之中的一個前,線程 T 被禁用,且處於休眠狀態:

  • 其它某個線程調用此對象的 notify 方法。而且線程 T 碰巧被任選為被喚醒的線程。

  • 其它某個線程調用此對象的 notifyAll 方法。
  • 其它某個線程中斷線程 T。

  • 大約已經到達指定的實際時間。可是,假設 timeout 為零,則不考慮實際時間。在獲得通知前該線程將一直等待。 然後。從對象的等待集中刪除線程 T。並又一次進行線程調度。然後,該線程以常規方式與其它線程競爭,以獲得在該對象上同步的權利。一旦獲得對該對象的控制權,該對象上的全部其同步聲明都將被恢復到曾經的狀態,這就是調用 wait 方法時的情況。

    然後,線程 T 從 wait 方法的調用中返回。所以。從 wait 方法返回時。該對象和線程 T 的同步狀態與調用 wait 方法時的情況全然同樣。

在沒有被通知、中斷或超時的情況下,線程還能夠喚醒一個所謂的虛假喚醒 (spurious wakeup)。盡管這樣的情況在實踐中非常少發生,可是應用程序必須通過以下方式防止其發生,即相應該導致該線程被提醒的條件進行測試。假設不滿足該條件,則繼續等待。

換句話說。等待應總是發生在循環中,如以下的演示樣例:
synchronized (obj) {
while (<condition does not hold>)
obj.wait(timeout);
... // Perform action appropriate to condition
}


7、wait(long timeout, int nanos):在其它線程調用此對象的 notify() 方法或 notifyAll() 方法,或者其它某個線程中斷當前線程,或者已超過某個實際時間量前。導致當前線程等待。

此方法類似於一個參數的 wait 方法,但它同意更好地控制在放棄之前等待通知的時間量。用毫微秒度量的實際時間量能夠通過下面公式計算出來:
1000000*timeout+nanos在其它全部方面。此方法運行的操作與帶有一個參數的 wait(long) 方法同樣。須要特別指出的是,wait(0, 0) 與 wait(0) 同樣。

當前線程必須擁有此對象監視器。該線程公布對此監視器的全部權,並等待以下兩個條件之中的一個發生:

  • 其它線程通過調用 notify 方法,或 notifyAll 方法通知在此對象的監視器上等待的線程醒來。
  • timeout 毫秒值與 nanos 毫微秒參數值之和指定的超時時間已用完。
然後,該線程等到又一次獲得對監視器的全部權後才幹繼續運行。
對於某一個參數的版本號,實現中斷和虛假喚醒是有可能的,而且此方法應始終在循環中使用:
synchronized (obj) {
while (<condition does not hold>)
obj.wait(timeout, nanos);
... // Perform action appropriate to condition
}

8、wait():在其它線程調用此對象的 notify() 方法或 notifyAll() 方法前,導致當前線程等待。換句話說。此方法的行為就好像它僅運行 wait(0) 調用一樣。


當前線程必須擁有此對象監視器。該線程公布對此監視器的全部權並等待,直到其它線程通過調用 notify 方法,或 notifyAll 方法通知在此對象的監視器上等待的線程醒來。

然後該線程將等到又一次獲得對監視器的全部權後才幹繼續運行。


對於某一個參數的版本號。實現中斷和虛假喚醒是可能的。並且此方法應始終在循環中使用:

synchronized (obj) {
while (<condition does not hold>)
obj.wait();
... // Perform action appropriate to condition
}


9、finalize():當垃圾回收器確定不存在對該對象的很多其它引用時,由對象的垃圾回收器調用此方法。

子類重寫 finalize 方法。以配置系統資源或運行其它清除。


finalize 的常規協定是:當 JavaTM 虛擬機已確定尚未終止的不論什麽線程無法再通過不論什麽方法訪問此對象時,將調用此方法。除非因為準備終止的其它某個對象或類的終結操作運行了某個操作。

finalize 方法能夠採取不論什麽操作,當中包含再次使此對象對其它線程可用;只是。finalize 的主要目的是在不可撤消地丟棄對象之前運行清除操作。比如。表示輸入/輸出連接的對象的 finalize 方法可運行顯式 I/O 事務。以便在永久丟棄對象之前中斷連接。


Object 類的 finalize 方法運行非特殊性操作;它僅運行一些常規返回。

Object 的子類能夠重寫此定義。


Java 編程語言不保證哪個線程將調用某個給定對象的 finalize 方法。但能夠保證在調用 finalize 時。調用 finalize 的線程將不會持有不論什麽用戶可見的同步鎖定。假設 finalize 方法拋出未捕獲的異常,那麽該異常將被忽略。而且該對象的終結操作將終止。


在啟用某個對象的 finalize 方法後,將不會運行進一步操作,直到 Java 虛擬機再次確定尚未終止的不論什麽線程無法再通過不論什麽方法訪問此對象,當中包含由準備終止的其它對象或類運行的可能操作,在運行該操作時。對象可能被丟棄。


對於不論什麽給定對象,Java 虛擬機最多僅僅調用一次 finalize 方法。


finalize 方法拋出的不論什麽異常都會導致此對象的終結操作停止,但能夠通過其它方法忽略它

深入研究java.lang.Object類