首先簡單的介紹一下Object類。java
java.lang.Objectc++
java.lang包使用的時候,不用顯示導入,由編譯器自動導入。多線程
Objec(即對象類)是JDK1.0就出現的,是類層次結構的根,是Java中的頂級父類,Java中全部的類都默認直接或者間接的繼承Object類。Objec是Java中惟一沒有父類的類,任何一個類的對象均可以用Object對象接收。以下:函數
//以下操做都是能夠的。 Object o1=new Object(); Object o2=new String(); Object o3=new ArrayList<>(); Object o4=new HashSet<>(); Object o5=new HashMap<>(); Object o6=new Integer(1);
而後咱們看一下,Object這個類的總體結構。this
如上圖,我使用的是1.8的jdk,總共13個方法,本博文將參照API文檔以及源碼進行介紹。spa
API文檔中構造方法中提供的全部構造方法默認是public修飾的。操作系統
API文檔中提供了:pulbic Object()的構造方法,在實際代碼中,沒有寫出,使用的是JVM提供的默認構造。.net
此方法用來克隆對象。克隆完成以後會產生一個新的對象,這個新對象和原對象的地址不一樣可是屬性值是同樣的。線程
此方法說的通俗一點,就是一間房子徹底仿照另一間房子建造,不一樣的只是位置,其餘的所有同樣。code
一個對象要想被克隆,那麼這個對象對應的類必須實現Cloneable接口,Cloneable接口中沒有任何的方法和屬性,僅僅用於標識這個類產生的對象能夠被克隆。
源碼以下:
//方法源碼 protected native Object clone() throws CloneNotSupportedException; //接口源碼 public interface Cloneable { }
此方法是一個受保護的本地方法。native關鍵字修飾的是本地方法,底層是用c/c++語言實現的,Java源碼中看不到其具體實現。
下面提供一個示例:
public class T1 implements Cloneable { int i; public static void main(String[] args) throws CloneNotSupportedException { T1 t = new T1(); t.i = 5; T1 t1 = (T1) t.clone(); System.out.println(t); System.out.println(t1); } }
此方法用於判斷兩個對象是否一致。
以下是源碼:
public boolean equals(Object obj) { return (this == obj); }
從源碼中能夠看出,默認使用的是==運算符,比較的是對象的地址,也能夠得出另一個結論,Object類中的equals方法等價於==。在開發中通常都要重寫這個方法。Eclipse中右鍵Sourec中有自動生成。
其實這些特色都是咱們很早就學過的數學上的相等的特色。如下說起的都是非空和不是NAN的狀況。
自反性:a.equals(a)結果爲true。即本身等於本身,數學上的1=1。
對稱性:a.equals(b)結果爲true,那麼在a和b都不發生改變的狀況下,b.equals(a)結果也爲true。即數學上的a=b,那麼b=a。
一致性:a.equals(b)結果爲true,那麼在a和b沒有發生過改變的狀況下a.equals(b)結果一直爲true。即a永遠和b相等,也就是1=1永遠都是這樣。
約定:a.equals(null)爲false,即非空a永遠不等於null。
只有當繼承Object的類重寫了equals方法以後,此類中的equals方法才和==纔有可能不一樣,但這兩個比較的使用的本質上仍是有一些不一樣。
拋開重寫不說,當比較的是基本類型的時候,==判斷的是實際數據,而且基本類型身上也沒有equals方法能夠調用。對於引用類型而言==判斷的是地址,equals則默認和==是同樣的。equals只能做用於引用類型,默認比較的是兩個對象的地址。
當重寫來equals的時候,按照重寫以後的邏輯進行比較。此時比較的邏輯才和==有很大的不一樣。
因此僅使用==是沒法完全判斷兩個對象是否相等,咱們須要針對equals方法進行重寫,步驟以下:
1.判斷地址是否同樣,即直接使用==運算符。
2.判斷對象是否爲空。
3.判斷對象的建立類型是否一致。
4.判斷屬性值是否一致。判斷以前要將對象強轉爲頂級父類。判斷屬性值的時候注意String類型的判斷。
示例:
Public boolean equals(Object obj){ if (this == obj) //1.判斷地址是否一致 return true; if (obj == null) //2.判斷參數是否爲空 return false; if (getClass() != obj.getClass()) //3.判斷類型是否一致 return false; Person other = (Person) obj; //4.強制轉換類別 if (age != other.age) //5.判斷屬性是否一致 return false; if (gender != other.gender) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; }
通知gc回收垃圾對象,可是垃圾回收器不必定執行。
源碼以下:
protected void finalize() throws Throwable { }
你沒有看錯,源碼是個空方法,即便gc開始運行,也只回收當前對象而不回收其餘對象。
首先,Object中定義finalize方法代表Java中每個對象都將具備finalize這種行爲,其具體調用時機在:JVM準備對此對形象所佔用的內存空間進行垃圾回收前,將被調用。由此能夠看出,此方法並非由咱們主動去調用的(雖然能夠主動去調用,此時與其餘自定義方法無異)。
類似的:System.gc();通知gc回收對象,不限制範圍。
獲取對象的實際類型(建立類型)。
Object o1=new Object(); o1.getClass(); //上面等同於下面 Object.class
視具體場景而定,使用哪一種方法實現獲取類型。
源碼以下:
public final native Class<?> getClass();
由源碼能夠看出,此方法也使用native修飾。
返回對象的哈希碼值的十進制。哈希碼是一串32位的二進制數據,因爲出現相同的數值的機率很是低,因此能夠認爲是惟一的。
源碼以下:
public native int hashCode();
由源碼能夠看出,此方法也使用native修飾。通常重寫equals方法的同時都會重寫這個方法。可是不建議手動重寫,使用IDE生成便可。
重寫hashCode的時候,當equals值爲true的時候,哈希碼必須一致。可是哈希碼一致equals不必定爲true。
返回該對象的字符串表示。當打印對象的時候默認是調用了這個對象的toString方法。通常會重寫。
源碼以下:
public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); }
該字符串由類名(對象是該類的一個實例)、at 標記符「@」和此對象哈希碼的無符號十六進制表示組成。換句話說,該方法返回一個字符串。因此切記不要搞混了,這裏默認返回的不是對象的內存地址。
registerNatives函數前面有native關鍵字修飾,Java中,用native關鍵字修飾的函數代表該方法的實現並非在Java中去完成,而是由C/C++去完成,並被編譯成了.dll,由Java去調用。方法的具體實現體在dll文件中,對於不一樣平臺,其具體實現應該有所不一樣。用native修飾,即表示操做系統,須要提供此方法,Java自己須要使用。具體到registerNatives()方法自己,其主要做用是將C/C++中的方法映射到Java中的native方法,實現方法命名的解耦。
既然如此,可能有人會問,registerNatives()修飾符爲private,且並無執行,做用何以達到?其實,在Java源碼中,此方法的聲明後有緊接着一段靜態代碼塊,以下:
private static native void registerNatives(); static { registerNatives(); }
以下是這幾個方法的源碼:
//喚醒在此對象監聽器上的單個等待的線程 public final native void notify(); //喚醒再次對象監聽器上的全部等待的線程 public final native void notifyAll(); //線程處於等待timeout的時長,使用以上兩個方法能夠提早喚醒,也能夠到時本身醒。 public final native void wait(long timeout) throws InterruptedException; //線程處於等待狀態,只能被notify()/notifyAll()方法喚醒。 public final void wait() throws InterruptedException { //調用的wait方法,可是沒有時長。 wait(0); } //timeout - 要等待的最長時間(以毫秒爲單位)。 //nanos - 額外時間(以毫微秒爲單位,範圍是 0-999999)。 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"); } //若是額外的時間大於500000毫微秒或者額外的時間不等於0等待時間爲0 if (nanos >= 500000 || (nanos != 0 && timeout == 0)) { //等待時間增長 timeout++; } //調用本地方法 wait(timeout); }