天天看點

一文帶你讀懂Object類源碼

Object類是一個比較特殊的類,是所有類的超級父類,java中如果一個類沒有用 extends關鍵字 明确指出繼承于某個類,那麼它預設繼承Object類。下面我們一起分析這個默默被所有類所繼承的 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 方法:對于任何繼承此類的導出類 或 其他任何位于同一個包内的類,方法是可以通路的。
一文帶你讀懂Object類源碼

常用方法清單

在jdk8中,Object 類的方法清單如下:

一文帶你讀懂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代碼的函數位址
一文帶你讀懂Object類源碼
一文帶你讀懂Object類源碼

方法1:clone()

Object類的 clone()方法,實作了對象中各個屬性的複制,但它的可見範圍是protected的,是以實體類使用克隆的前提是:

  1. 實作Cloneable接口,這是一個标記接口,自身沒有方法。 
  2. 覆寫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=北京))           
一文帶你讀懂Object類源碼

方法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           
一文帶你讀懂Object類源碼

方法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 :(           
一文帶你讀懂Object類源碼

方法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類。

一文帶你讀懂Object類源碼

方法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&trade; 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);              }           
一文帶你讀懂Object類源碼

方法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();           
一文帶你讀懂Object類源碼

方法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());              }           
一文帶你讀懂Object類源碼

方法9~11:wait()/wait(long)/wait(long, int)

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

一文帶你讀懂Object類源碼

方法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類源碼

總結

Object 類位于 java.lang 包中,編譯時會自動導入。了解Object 超類,有助于閱讀JDK源碼,了解多線程機制。

一文帶你讀懂Object類源碼

—END—

掃描二維碼

擷取技術幹貨

背景技術彙

一文帶你讀懂Object類源碼