Object【Java源碼分析】
- 前言
- 推薦
- 說明
- Object類
- 基本資訊
- 構造方法摘要
- 方法摘要
- 構造方法詳細資訊
- 方法詳細資訊
- getClass
- hashCode
- equals
- clone
- toString
- notify
- notifyAll
- wait
- wait
- wait
- finalize
- 測試
- 總結
- 最後
前言
2022/10/24
路漫漫其修遠兮,吾将上下而求索
本文是根據jdk學習所做筆記
僅供學習交流使用,轉載注明出處
推薦
JDK API 1.6 中文版
說明
以下内容是結合很多資料進行編寫的
源碼為jdk1.8的
斜體樣式 為自己的思考
下劃線為自己所畫的重點
Object類
基本資訊
java.lang
類 Object
java.lang.Object
public class Object
類 Object 是類層次結構的根類。每個類都使用 Object 作為超類。所有對象(包括數組)都實作這個類的方法。
從以下版本開始:
JDK1.0
另請參見:
Class
構造方法摘要
Object()
方法摘要
修飾符 | 方法名 | 描述 |
protected Object | clone() | 建立并傳回此對象的一個副本。 |
boolean | equals(Object obj) | 訓示其他某個對象是否與此對象“相等”。 |
protected | void finalize() | 當垃圾回收器确定不存在對該對象的更多引用時,由對象的垃圾回收器調用此方法。 |
Class<?> | getClass() | 傳回此 Object 的運作時類。 |
int | hashCode() | 傳回該對象的哈希碼值。 |
void | notify() | 喚醒在此對象螢幕上等待的單個線程。 |
void | notifyAll() | 喚醒在此對象螢幕上等待的所有線程。 |
String | toString() | 傳回該對象的字元串表示。 |
void | wait() | 在其他線程調用此對象的 notify() 方法或 notifyAll() 方法前,導緻目前線程等待。 |
void | wait(long timeout) | 在其他線程調用此對象的 notify() 方法或 notifyAll() 方法,或者超過指定的時間量前,導緻目前線程等待。 |
void | wait(long timeout, int nanos) | 在其他線程調用此對象的 notify() 方法或 notifyAll() 方法,或者其他某個線程中斷目前線程,或者已超過某個實際時間量前,導緻目前線程等待。 |
構造方法詳細資訊
Object
public Object()
方法詳細資訊
getClass
public final Class<?> getClass()傳回此 Object 的運作時類。傳回的 Class 對象是由所表示類的 static synchronized 方法鎖定的對象。
實際結果類型是 Class<? extends |X|>,其中 |X| 表示清除表達式中的靜态類型,該表達式調用 getClass。 例如,以下代碼片段中不需要強制轉換:
Number n = 0;
Class<? extends Number> c = n.getClass();
傳回:
表示此對象運作時類的 Class 對象。
另請參見:
The Java Language Specification, Third Edition (15.8.2 Class Literals)
public final native Class<?> getClass();
hashCode
public int hashCode()
傳回該對象的哈希碼值。支援此方法是為了提高哈希表(例如 java.util.Hashtable 提供的哈希表)的性能。
hashCode 的正常協定是:
- 在 Java 應用程式執行期間,在對同一對象多次調用 hashCode 方法時,必須一緻地傳回相同的整數,前提是将對象進行 equals 比較時所用的資訊沒有被修改。從某一應用程式的一次執行到同一應用程式的另一次執行,該整數無需保持一緻。
- 如果根據 equals(Object) 方法,兩個對象是相等的,那麼對這兩個對象中的每個對象調用 hashCode 方法都必須生成相同的整數結果。
- 如果根據 equals(java.lang.Object) 方法,兩個對象不相等,那麼對這兩個對象中的任一對象上調用 hashCode 方法 不 要求一定生成不同的整數結果。但是,程式員應該意識到,為不相等的對象生成不同整數結果可以提高哈希表的性能。
實際上,由 Object 類定義的 hashCode 方法确實會針對不同的對象傳回不同的整數。(這一般是通過将該對象的内部位址轉換成一個整數來實作的,但是 Java™ 程式設計語言不需要這種實作技巧。)
傳回:
此對象的一個哈希碼值。
另請參見:
equals(java.lang.Object), Hashtable
public native int hashCode();
equals
public boolean equals(Object 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。
Object 類的 equals 方法實作對象上差别可能性最大的相等關系;即,對于任何非空引用值 x 和 y,當且僅當 x 和 y 引用同一個對象時,此方法才傳回 true(x == y 具有值 true)。
注意:當此方法被重寫時,通常有必要重寫 hashCode 方法,以維護 hashCode 方法的正常協定,該協定聲明相等對象必須具有相等的哈希碼。
參數:
obj - 要與之比較的引用對象。
傳回:
如果此對象與 obj 參數相同,則傳回 true;否則傳回 false。
另請參見:
hashCode(), Hashtable
public boolean equals(Object obj) {
return (this == obj);
}
clone
protected Object clone()
throws CloneNotSupportedException
建立并傳回此對象的一個副本。“副本”的準确含義可能依賴于對象的類。這樣做的目的是,對于任何對象 x,表達式:
x.clone() != x為 true,
表達式:
x.clone().getClass() == x.getClass()
也為 true,但這些并非必須要滿足的要求。一般情況下:
x.clone().equals(x)
為 true,但這并非必須要滿足的要求。
按照慣例,傳回的對象應該通過調用 super.clone 獲得。如果一個類及其所有的超類(Object 除外)都遵守此約定,則 x.clone().getClass() == x.getClass()。
按照慣例,此方法傳回的對象應該獨立于該對象(正被複制的對象)。要獲得此獨立性,在 super.clone 傳回對象之前,有必要對該對象的一個或多個字段進行修改。這通常意味着要複制包含正在被複制對象的内部“深層結構”的所有可變對象,并使用對副本的引用替換對這些對象的引用。如果一個類隻包含基本字段或對不變對象的引用,那麼通常不需要修改 super.clone 傳回的對象中的字段。
Object 類的 clone 方法執行特定的複制操作。首先,如果此對象的類不能實作接口 Cloneable,則會抛出 CloneNotSupportedException。注意,所有的數組都被視為實作接口 Cloneable。否則,此方法會建立此對象的類的一個新執行個體,并像通過配置設定那樣,嚴格使用此對象相應字段的内容初始化該對象的所有字段;這些字段的内容沒有被自我複制。是以,此方法執行的是該對象的“淺表複制”,而不“深層複制”操作。
Object 類本身不實作接口 Cloneable,是以在類為 Object 的對象上調用 clone 方法将會導緻在運作時抛出異常。
傳回:
此執行個體的一個副本。
抛出:
CloneNotSupportedException - 如果對象的類不支援 Cloneable 接口,則重寫 clone 方法的子類也會抛出此異常,以訓示無法複制某個執行個體。
另請參見:
Cloneable
//本地方法:把共用同一段記憶體
protected native Object clone() throws CloneNotSupportedException;
toString
public String toString()
傳回該對象的字元串表示。通常,toString 方法會傳回一個“以文本方式表示”此對象的字元串。結果應是一個簡明但易于讀懂的資訊表達式。建議所有子類都重寫此方法。
Object 類的 toString 方法傳回一個字元串,該字元串由類名(對象是該類的一個執行個體)、at 标記符“@”和此對象哈希碼的無符号十六進制表示組成。換句話說,該方法傳回一個字元串,它的值等于:
getClass().getName() + ‘@’ + Integer.toHexString(hashCode())
傳回:
該對象的字元串表示形式。
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
notify
public final void notify()
喚醒在此對象螢幕上等待的單個線程。如果所有線程都在此對象上等待,則會選擇喚醒其中一個線程。選擇是任意性的,并在對實作做出決定時發生。線程通過調用其中一個 wait 方法,在對象的螢幕上等待。
直到目前線程放棄此對象上的鎖定,才能繼續執行被喚醒的線程。被喚醒的線程将以正常方式與在該對象上主動同步的其他所有線程進行競争;例如,喚醒的線程在作為鎖定此對象的下一個線程方面沒有可靠的特權或劣勢。
此方法隻應由作為此對象螢幕的所有者的線程來調用。通過以下三種方法之一,線程可以成為此對象螢幕的所有者:
- 通過執行此對象的同步執行個體方法。
- 通過執行在此對象上進行同步的 synchronized 語句的正文。
- 對于 Class 類型的對象,可以通過執行該類的同步靜态方法。
一次隻能有一個線程擁有對象的螢幕。
抛出:
IllegalMonitorStateException - 如果目前線程不是此對象螢幕的所有者。
另請參見:
notifyAll(), wait()
public final native void notify();
notifyAll
public final void notifyAll()
喚醒在此對象螢幕上等待的所有線程。線程通過調用其中一個 wait 方法,在對象的螢幕上等待。
直到目前線程放棄此對象上的鎖定,才能繼續執行被喚醒的線程。被喚醒的線程将以正常方式與在該對象上主動同步的其他所有線程進行競争;例如,喚醒的線程在作為鎖定此對象的下一個線程方面沒有可靠的特權或劣勢。
此方法隻應由作為此對象螢幕的所有者的線程來調用。有關線程能夠成為螢幕所有者的方法的描述,請參閱 notify 方法。
抛出:
IllegalMonitorStateException - 如果目前線程不是此對象螢幕的所有者。
另請參見:
notify(), wait()
public final native void notifyAll();
wait
public final void wait(long timeout)
throws InterruptedException
在其他線程調用此對象的 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
}
(有關這一主題的更多資訊,請參閱 Doug Lea 撰寫的 Concurrent Programming in Java (Second Edition) (Addison-Wesley, 2000) 中的第 3.2.3 節或 Joshua Bloch 撰寫的 Effective Java Programming Language Guide (Addison-Wesley, 2001) 中的第 50 項。
用while而不能用if的原因就是存在虛假喚醒
如果目前線程在等待之前或在等待時被任何線程中斷,則會抛出 InterruptedException。在按上述形式恢複此對象的鎖定狀态時才會抛出此異常。
注意,由于 wait 方法将目前線程放入了對象的等待集中,是以它隻能解除此對象的鎖定;可以同步目前線程的任何其他對象線上程等待時仍處于鎖定狀态。
此方法隻應由作為此對象螢幕的所有者的線程來調用。有關線程能夠成為螢幕所有者的方法的描述,請參閱 notify 方法。
參數:
timeout - 要等待的最長時間(以毫秒為機關)。
抛出:
IllegalArgumentException - 如果逾時值為負。
IllegalMonitorStateException - 如果目前線程不是此對象螢幕的所有者。
InterruptedException - 如果在目前線程等待通知之前或者正在等待通知時,任何線程中斷了目前線程。在抛出此異常時,目前線程的中斷狀态 被清除。
另請參見:
notify(), notifyAll()
public final native void wait(long timeout) throws InterruptedException;
wait
public final void wait(long timeout,
int nanos)
throws InterruptedException
在其他線程調用此對象的 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
}
此方法隻應由作為此對象螢幕的所有者的線程來調用。有關線程能夠成為螢幕所有者的方法的描述,請參閱 notify 方法。
參數:
timeout - 要等待的最長時間(以毫秒為機關)。
nanos - 額外時間(以毫微秒為機關,範圍是 0-999999)。
抛出:
IllegalArgumentException - 如果逾時值是負數,或者毫微秒值不在 0-999999 範圍内。
IllegalMonitorStateException - 如果目前線程不是此對象螢幕的所有者。
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);
}
wait
public final void wait()
throws InterruptedException
在其他線程調用此對象的 notify() 方法或 notifyAll() 方法前,導緻目前線程等待。換句話說,此方法的行為就好像它僅執行 wait(0) 調用一樣。
目前線程必須擁有此對象螢幕。該線程釋出對此螢幕的所有權并等待,直到其他線程通過調用 notify 方法,或 notifyAll 方法通知在此對象的螢幕上等待的線程醒來。然後該線程将等到重新獲得對螢幕的所有權後才能繼續執行。
對于某一個參數的版本,實作中斷和虛假喚醒是可能的,而且此方法應始終在循環中使用:
synchronized (obj) {
while (<condition does not hold>)
obj.wait();
... // Perform action appropriate to condition
}
此方法隻應由作為此對象螢幕的所有者的線程來調用。有關線程能夠成為螢幕所有者的方法的描述,請參閱 notify 方法。
抛出:
IllegalMonitorStateException - 如果目前線程不是此對象螢幕的所有者。
InterruptedException - 如果在目前線程等待通知之前或者正在等待通知時,任何線程中斷了目前線程。在抛出此異常時,目前線程的中斷狀态 被清除。
另請參見:
notify(), notifyAll()
public final void wait() throws InterruptedException {
wait(0);
}
finalize
protected void finalize()
throws Throwable
當垃圾回收器确定不存在對該對象的更多引用時,由對象的垃圾回收器調用此方法。子類重寫 finalize 方法,以配置系統資源或執行其他清除。
finalize 的正常協定是:當 Java™ 虛拟機已确定尚未終止的任何線程無法再通過任何方法通路此對象時,将調用此方法,除非由于準備終止的其他某個對象或類的終結操作執行了某個操作。finalize 方法可以采取任何操作,其中包括再次使此對象對其他線程可用;不過,finalize 的主要目的是在不可撤消地丢棄對象之前執行清除操作。例如,表示輸入/輸出連接配接的對象的 finalize 方法可執行顯式 I/O 事務,以便在永久丢棄對象之前中斷連接配接。
Object 類的 finalize 方法執行非特殊性操作;它僅執行一些正常傳回。Object 的子類可以重寫此定義。
Java 程式設計語言不保證哪個線程将調用某個給定對象的 finalize 方法。但可以保證在調用 finalize 時,調用 finalize 的線程将不會持有任何使用者可見的同步鎖定。如果 finalize 方法抛出未捕獲的異常,那麼該異常将被忽略,并且該對象的終結操作将終止。
在啟用某個對象的 finalize 方法後,将不會執行進一步操作,直到 Java 虛拟機再次确定尚未終止的任何線程無法再通過任何方法通路此對象,其中包括由準備終止的其他對象或類執行的可能操作,在執行該操作時,對象可能被丢棄。
對于任何給定對象,Java 虛拟機最多隻調用一次 finalize 方法。
finalize 方法抛出的任何異常都會導緻此對象的終結操作停止,但可以通過其他方法忽略它。
抛出:
Throwable - 此方法抛出的 Exception
protected void finalize() throws Throwable { }
測試
package testlang;
import java.util.Arrays;
import java.util.Objects;
/**
* @author CSDN@日星月雲
* @date 2022/10/24 16:58
*/
public class TestObject {
public static void main(String[] args) throws CloneNotSupportedException {
Object o = new Object();
System.out.println(o.getClass());//class java.lang.Object
System.out.println(o.getClass().getName());//java.lang.Object
//預設使用toString()
System.out.println(o); //java.lang.Object@1b6d3586
System.out.println(o.toString());//java.lang.Object@1b6d3586
OUser ou1=new OUser();
ou1.id=1;
ou1.name="1";
System.out.println(ou1.equals(ou1));//true
OUser ou2=new OUser();
ou2.id=1;
ou2.name="1";
System.out.println(ou1.hashCode());//460141958
System.out.println(ou2.hashCode());//1163157884
System.out.println(ou1.equals(ou2));//false
//重寫hashCode和equals之後
System.out.println(ou1.hashCode());//1041
System.out.println(ou2.hashCode());//1041
System.out.println(ou1.equals(ou2));//true
//重寫toString()之後
System.out.println(ou1); //OUser{id=1, name='1'}
System.out.println(ou1.toString());//OUser{id=1, name='1'}
//實作clone之前
// ou1.test= new int[]{1, 2, 3};
// OUser clone = (OUser) ou1.clone();
// System.out.println(clone);
// clone.name="2";
// clone.test[0]=2;
// System.out.println(ou1); //OUser{id=1, name='1', test=[2, 2, 3]}
// System.out.println(clone);//OUser{id=1, name='2', test=[2, 2, 3]}
/*
* 結果:請拷貝
* 但Sting類是不可變性質 ou1.name-->"1" clone.name-->"2"
* 而int[] 沒有實作,是以要重寫clone 而不是用 return super.clone();
*/
//重寫clone實作深拷貝 原型模式
//實作clone之後
ou1.test= new int[]{1, 2, 3};
OUser clone = (OUser) ou1.clone();
System.out.println(clone);
clone.name="2";
clone.test[0]=2;
System.out.println(ou1); //OUser{id=1, name='1', test=[1, 2, 3]}
System.out.println(clone);//OUser{id=1, name='2', test=[2, 2, 3]}
}
}
class OUser implements Cloneable{
int id;
String name;
int [] test;
//重寫hashCode和equals
@Override
public boolean equals(Object o) {
//是否是同一對象==
if (this == o) return true;
//它的類class是否相同
if (o == null || getClass() != o.getClass()) return false;
//Object->OUser
OUser oUser = (OUser) o;
//判斷内容是否相同 //String類重寫了Objects 不再是==,也是比較其内容
return id == oUser.id && Objects.equals(name, oUser.name);
}
@Override
public int hashCode() {
//Objects工具類的hash()
return Objects.hash(id, name);
}
/**
* Objects
* public static int hash(Object... values) {
* return Arrays.hashCode(values);
* }
*
*Arrays
*public static int hashCode(Object a[]) {
* if (a == null)
* return 0;
*
* int result = 1;
*
* for (Object element : a)
* result = 31 * result + (element == null ? 0 : element.hashCode());
*
* return result;
* }
*
* Object
* public native int hashCode();
*/
//重寫toString
// @Override
// public String toString() {
// return "OUser{" +
// "id=" + id +
// ", name='" + name + '\'' +
// '}';
// }
//測試clone
@Override
public String toString() {
return "OUser{" +
"id=" + id +
", name='" + name + '\'' +
", test=" + Arrays.toString(test) +
'}';
}
// @Override
// protected Object clone() throws CloneNotSupportedException {
// return super.clone();
// }
//實作clone方法
@Override
protected Object clone() throws CloneNotSupportedException {
int id=this.id;
String name=new String(this.name);
int[] test = Arrays.copyOf(this.test, this.test.length);
OUser clone=new OUser();
clone.id=id;
clone.name=name;
clone.test=test;
return clone;
}
}
總結
- hashCode
- equals
- clone
- toString
- finalize
- wait
- 虛假喚醒
- notify