Java API:Object class

Java API:Object class

    首先簡單的介紹一下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

二、重要方法

1.clone();

    此方法用來克隆對象。克隆完成以後會產生一個新的對象,這個新對象和原對象的地址不一樣可是屬性值是同樣的。線程

    此方法說的通俗一點,就是一間房子徹底仿照另一間房子建造,不一樣的只是位置,其餘的所有同樣。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);
	}
}

2.equals(Object obj)

    此方法用於判斷兩個對象是否一致。

    以下是源碼:

public boolean equals(Object obj) {
        return (this == obj);
    }

    從源碼中能夠看出,默認使用的是==運算符,比較的是對象的地址,也能夠得出另一個結論,Object類中的equals方法等價於==。在開發中通常都要重寫這個方法。Eclipse中右鍵Sourec中有自動生成。

equals方法的特色

    其實這些特色都是咱們很早就學過的數學上的相等的特色。如下說起的都是非空和不是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。

==和equals有什麼區別

    只有當繼承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;
	}

3.finalize()

    通知gc回收垃圾對象,可是垃圾回收器不必定執行。

    源碼以下:

protected void finalize() throws Throwable { }

    你沒有看錯,源碼是個空方法,即便gc開始運行,也只回收當前對象而不回收其餘對象。

    首先,Object中定義finalize方法代表Java中每個對象都將具備finalize這種行爲,其具體調用時機在:JVM準備對此對形象所佔用的內存空間進行垃圾回收前,將被調用。由此能夠看出,此方法並非由咱們主動去調用的(雖然能夠主動去調用,此時與其餘自定義方法無異)。

    類似的:System.gc();通知gc回收對象,不限制範圍。

4.getClass();獲取類型

    獲取對象的實際類型(建立類型)。

Object o1=new Object();
o1.getClass();
//上面等同於下面
Object.class

    視具體場景而定,使用哪一種方法實現獲取類型。

    源碼以下:

public final native Class<?> getClass();

    由源碼能夠看出,此方法也使用native修飾。

5.hashCode();返回哈希碼

    返回對象的哈希碼值的十進制。哈希碼是一串32位的二進制數據,因爲出現相同的數值的機率很是低,因此能夠認爲是惟一的。

    源碼以下:

public native int hashCode();

    由源碼能夠看出,此方法也使用native修飾。通常重寫equals方法的同時都會重寫這個方法。可是不建議手動重寫,使用IDE生成便可。

    重寫hashCode的時候,當equals值爲true的時候,哈希碼必須一致。可是哈希碼一致equals不必定爲true。

6.toString();返回對象的字符串形式

    返回該對象的字符串表示。當打印對象的時候默認是調用了這個對象的toString方法。通常會重寫。

    源碼以下:

public String toString() {
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }

    該字符串由類名(對象是該類的一個實例)、at 標記符「@」和此對象哈希碼的無符號十六進制表示組成。換句話說,該方法返回一個字符串。因此切記不要搞混了,這裏默認返回的不是對象的內存地址。

7.registerNatives()

    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();
    }

8.多線程相關的方法

    以下是這幾個方法的源碼:

//喚醒在此對象監聽器上的單個等待的線程
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);
}

 

上一篇:面向對象(object-oriented:OO)

下一篇:Java API:String class

相關文章
相關標籤/搜索