Object類是一個比較特殊的類,是所有類的超級父類,java中如果一個類沒有用 extends關鍵字 明确指出繼承于某個類,那麼它預設繼承Object類。下面我們一起分析這個默默被所有類所繼承的 Object。

Object 設計要點
Object 類是Java中所有類的父類,作為最重要的基類,它提供了12個預設實作方法(jdk8)。
在解析每個方法的功能實作和用途之前,我們需要了解幾個概念:
- Monitor:java中每個對象都有唯一的一個monitor,在Java的設計中,每一個對象自打娘胎裡出來,就帶了一把看不見的鎖,通常我們叫“内部鎖”,或者“Monitor鎖”。
- 對象鎖池:每個java對象都擁有兩個池,分别為鎖池(EntrySet)和(WaitSet)等待池。
鎖池:假如已經有線程A擷取到了鎖,這時候又有線程B需要擷取這把鎖(比如需要調用synchronized修飾的方法或者需要執行synchronized修飾的代碼塊),由于該鎖已經被占用,是以線程B隻能等待這把鎖,這時候線程B将會進入這把鎖的鎖池。
等待池:假設線程A擷取到鎖之後,由于一些條件的不滿足(例如生産者消費者模式中生産者擷取到鎖,然後判斷隊列為滿),此時需要調用對象鎖的wait方法,那麼線程A将放棄這把鎖,并進入這把鎖的等待池。
- Native 方法:本地方法,基于C/C++實作的方法。本地方法用法可以參考文章《謹慎的使用本地方法》。
- static 方法塊:static{} 靜态代碼塊會在JVM加載類之前執行。執行優先級高于非靜态的初始化塊,它會在類初始化的時候執行一次,執行完成便銷毀,它僅能初始化類變量,即static修飾的資料成員。
- protected 方法:對于任何繼承此類的導出類 或 其他任何位于同一個包内的類,方法是可以通路的。

常用方法清單
在jdk8中,Object 類的方法清單如下:
方法名稱 | 功能 | 備注 |
clone | 克隆對象 | 淺複制(基礎類型資料與複合對象的引用會被直接拷貝) |
equal | 比較對象 | 預設依賴hashCode()方法 |
finalize | 告訴GC可以回收該對象,但真正回收時機得交由GC來判斷 | |
getClass | 擷取運作時類型 | |
hashCode | 擷取對象哈希Code | |
notify | 喚醒該對象的放在等待池的某個線程 | |
notifyAll | 喚醒該對象的等待池的所有線程 | |
toString | 傳回辨別對象的字元串,預設格式(getClass().getName() + '@' + Integer.toHexString(hashCode())) | |
wait()/wait(long)/wait(long, int) | 讓出目标對象監聽器,使目前線程将自己置于該目标對象的等待池中 | |
registerNatives | 将class裡面native的方法的位址+1指向執行的c代碼的函數位址 |

方法1:clone()
Object類的 clone()方法,實作了對象中各個屬性的複制,但它的可見範圍是protected的,是以實體類使用克隆的前提是:
- 實作Cloneable接口,這是一個标記接口,自身沒有方法。
- 覆寫clone()方法,可見性提升為public。
public class TestClone { public static void main(String[] args) throws CloneNotSupportedException { Address address=new Address(); address.setType("Home"); address.setValue("北京"); Personclone p1=new Personclone(); p1.setAge(31); p1.setName("Peter"); p1.setAddress(address); Personclone p2=(Personclone) p1.clone(); System.out.println("p1 == p2:" + (p1==p2)); System.out.println("p1="+p1); System.out.println("p2="+p2); } } @Data class Personclone implements Cloneable { private String name; private Integer age; private Address address; @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } } @Data class Address { private String type; private String value; }
輸出結果:
p1 == p2:false p1=Personclone(name=Peter, age=31, address=Address(type=Home, value=北京)) p2=Personclone(name=Peter, age=31, address=Address(type=Home, value=北京))
方法2:equal()
Object 類預設實作的 equal():“==”比較兩個變量本身的值,即兩個對象在記憶體中的首位址。
源碼:
public boolean equals(Object obj) { return (this == obj); }
例子:
public class TestEqual { public static void main(String[] args) { Address address1 = new Address(); Person person = new Person(11); System.out.println("address1.equals(person):" + address1.equals(person)); } }
address1.equals(person):false
方法3:finalize()
Object 類的finalize() 作用是“呼叫”垃圾回收器:該對象已經沒有被任何地方所引用了,可以被回收。
Java 有GC 負責回收無用對象占據的記憶體資源,但也有特殊情況:假定你的對象(并非使用new)獲得了一塊“特殊”的記憶體區域,由于GC 隻知道釋放經過new方式配置設定的記憶體,是以它不知道該如何釋放該對象的“特殊”記憶體。是以,為了應對這種情況,Java運作在類中定義一個 finalize() 的方法。
finalize() 方法什麼時候被調用?
垃圾回收器(garbage collector)決定回收某對象時,就會運作該對象的finalize()方法;而System.gc()與System.runFinalization()方法增加了finalize方法執行的機會,但不可盲目依賴它們(避免使用終結方法)。
下面是使用覆寫使用 finalize() 方法的案例:
/** * REMARK * JVM : 一次對象的自我拯救示範 * finalize 方法:任何一個對象的finalize方法都隻會被系統自動調用一次(盡量避免使用它) */ public class FinalizeEscapeGC { public static FinalizeEscapeGC SAVE_HOOK = null; public void isAlive(){ System.out.println("yes, i am still alive:) "); } @Override protected void finalize() throws Throwable { // 覆寫實作finalize方法 super.finalize(); System.out.println("finalize method executed!"); FinalizeEscapeGC.SAVE_HOOK = this; } public static void main(String[] args) throws Throwable { SAVE_HOOK = new FinalizeEscapeGC(); // 對象第一次拯救自己 SAVE_HOOK = null; System.gc(); //觸發使用finalize() // 因為finalize方法優先級很低,是以暫停 0.5s 等待它 Thread.sleep(500); if (SAVE_HOOK != null){ SAVE_HOOK.isAlive(); } else { System.out.println("first time check,no, i am dead :("); } // 下面這段代碼和上面的完全相同,但是這次自救卻失敗了 SAVE_HOOK = null; System.gc(); // 因為finalize方法優先級很低,是以暫停 0.5s 等待它 Thread.sleep(500); if (SAVE_HOOK != null){ SAVE_HOOK.isAlive(); } else { System.out.println("second time check, no, i am dead :("); } } }
finalize method executed! yes, i am still alive:) second time check, no, i am dead :(

方法4:getClass()
Object 類的 getClass() 傳回運作時類資訊。
/** * Returns the runtime class of this {@code Object}. The returned * {@code Class} object is the object that is locked by {@code * static synchronized} methods of the represented class. * * <p><b>The actual result type is {@code Class<? extends |X|>} * where {@code |X|} is the erasure of the static type of the * expression on which {@code getClass} is called.</b> For * example, no cast is required in this code fragment:</p> * * <p> * {@code Number n = 0; }<br> * {@code Class<? extends Number> c = n.getClass(); } * </p> * * @return The {@code Class} object that represents the runtime * class of this object. * @jls 15.8.2 Class Literals */ public final native Class<?> getClass();
那麼Class類是什麼呢?
在Java中用來表示運作時類型資訊的對應類就是Class類,Class類也是一個實實在在的類,存在于JDK的java.lang包中。類資訊包括了:類名稱、包路徑、構造器、字段屬性、方法、父類結構等等。我們通常使用的反射就用到了Class類。

方法5:hashCode()
Object 類的 hashCode() 傳回辨別目前對象的唯一hash值。
/** * Returns a hash code value for the object. This method is * supported for the benefit of hash tables such as those provided by * {@link java.util.HashMap}. * <p> * The general contract of {@code hashCode} is: * <ul> * <li>Whenever it is invoked on the same object more than once during * an execution of a Java application, the {@code hashCode} method * must consistently return the same integer, provided no information * used in {@code equals} comparisons on the object is modified. * This integer need not remain consistent from one execution of an * application to another execution of the same application. * <li>If two objects are equal according to the {@code equals(Object)} * method, then calling the {@code hashCode} method on each of * the two objects must produce the same integer result. * <li>It is <em>not</em> required that if two objects are unequal * according to the {@link java.lang.Object#equals(java.lang.Object)} * method, then calling the {@code hashCode} method on each of the * two objects must produce distinct integer results. However, the * programmer should be aware that producing distinct integer results * for unequal objects may improve the performance of hash tables. * </ul> * <p> * As much as is reasonably practical, the hashCode method defined by * class {@code Object} does return distinct integers for distinct * objects. (This is typically implemented by converting the internal * address of the object into an integer, but this implementation * technique is not required by the * Java™ programming language.) * * @return a hash code value for this object. * @see java.lang.Object#equals(java.lang.Object) * @see java.lang.System#identityHashCode */ public native int hashCode();
hashCode() 方法應用場景非常多,比如HashMap:在jdk8中,HashMap.put(Key K, Value V) ,将節點添加到連結清單或者紅黑樹時,會利用對象的hashcode 判斷是否沖突。
static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); }

方法6~7:notify()/notifyAll()
Object 類的 notify()/notifyAll 會從等待擷取該對象Monitor鎖的線程池中,喚醒一個/全部線程,它們是本地final方法,無法被重寫。
/** * Wakes up a single thread that is waiting on this object's * monitor. If any threads are waiting on this object, one of them * is chosen to be awakened. The choice is arbitrary and occurs at * the discretion of the implementation. A thread waits on an object's * monitor by calling one of the {@code wait} methods. * <p> * The awakened thread will not be able to proceed until the current * thread relinquishes the lock on this object. The awakened thread will * compete in the usual manner with any other threads that might be * actively competing to synchronize on this object; for example, the * awakened thread enjoys no reliable privilege or disadvantage in being * the next thread to lock this object. * <p> * This method should only be called by a thread that is the owner * of this object's monitor. A thread becomes the owner of the * object's monitor in one of three ways: * <ul> * <li>By executing a synchronized instance method of that object. * <li>By executing the body of a {@code synchronized} statement * that synchronizes on the object. * <li>For objects of type {@code Class,} by executing a * synchronized static method of that class. * </ul> * <p> * Only one thread at a time can own an object's monitor. * * @throws IllegalMonitorStateException if the current thread is not * the owner of this object's monitor. * @see java.lang.Object#notifyAll() * @see java.lang.Object#wait() */ public final native void notify();

方法8:toString()
Object 類的 toString() 會預設傳回目前對象hashcode的十六進制字元串。
/** * Returns a string representation of the object. In general, the * {@code toString} method returns a string that * "textually represents" this object. The result should * be a concise but informative representation that is easy for a * person to read. * It is recommended that all subclasses override this method. * <p> * The {@code toString} method for class {@code Object} * returns a string consisting of the name of the class of which the * object is an instance, the at-sign character `{@code @}', and * the unsigned hexadecimal representation of the hash code of the * object. In other words, this method returns a string equal to the * value of: * <blockquote> * <pre> * getClass().getName() + '@' + Integer.toHexString(hashCode()) * </pre></blockquote> * * @return a string representation of the object. */ public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); }

方法9~11:wait()/wait(long)/wait(long, int)
Object 的 wait()/wait(long)/wait(long timeout, int nanos) 方法讓目前線程處于等待(阻塞)狀态,直到其他線程調用此對象的 notify() 方法或 notifyAll() 方法,或者超過參數 timeout 與 nanos 設定的逾時時間。

方法12:registerNatives()
registerNatives()方法存在于Object類、Class類、ClassLoader類等常用的類中。
private static native void registerNatives(); static { registerNatives(); }
Native method是由非Java語言實作的方法。通常Java中的native方法的常是C/C++實作,Java中提供了與其他語言通信的API即JNI(Java Native Interface)。如果要使用Java調用其它語言的函數,就必須遵循JNI的API約定。

總結
Object 類位于 java.lang 包中,編譯時會自動導入。了解Object 超類,有助于閱讀JDK源碼,了解多線程機制。
—END—
掃描二維碼
擷取技術幹貨
背景技術彙