1. 程式人生 > >Java基礎知識回顧之Object類

Java基礎知識回顧之Object類

簡介

類Object是類層次結構的根類。每個類都使用Object作為超類。所有物件(包括陣列)都實現這個類的所有方法。我們接觸到的元素有:物件、陣列、介面等,這麼多的元素為了方便統一,就可以使用 Object。

任何一個類在定義的時候如果沒有明確的繼承一個父類的話,那麼他就是Object類的子類。

public class TestDemo {
}

// 等價於:

public class TestDemo extends Object{
}

當我們看官方文件時,會發現 Object 類會有一個無參的構造方法。這個是因為:Object 類是所有類的父類,那麼所有類的物件例項化的時候,子類構造方法一定要預設呼叫父類的無參構造。

Object類的常用方法

從嚴格意義上面來(一般不遵守)說,任何一個簡單的Java類都應該覆寫 Object 類中的以下方法:

  • 獲取物件資訊: public String toString();
  • 物件比較: public boolean equals(Object object)
  • 取得物件 HASH 碼:public int hashCode()

toString()

如果是一個 String 類的物件,直接輸出這個物件可以獲取到字串的內容,但是輸出一個自定義的物件,就一個物件編碼。

public class TestDemo {

	public
static void main(String[] args) { String str = "Object字串"; TestDemo ts = new TestDemo(); System.out.println(str); // Object字串 // 當我們在輸出物件的時候,會自動呼叫物件中的 toString() 方法將物件變為字串之後再輸出。 System.out.println(ts); // [email protected] System.out.println(ts.toString()); // [email protected]
} }

當我們看 Object 類的原始碼的時候會發現 toString() 方法如下:

 /*
    返回該物件的字串表示,非常重要的方法
    getClass().getName();獲取位元組碼檔案的對應全路徑名例如java.lang.Object
    Integer.toHexString(hashCode());將雜湊值轉成16進位制數格式的字串。
    */
    public String toString(){
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }

但是我們發現 String類 的 toString() 方法輸出的結果不一樣,我們開啟 String 類的方法,可以看到 String 類是將 toString() 方法重寫了:

/**
 * This object (which is already a string!) is itself returned.
 *
 * @return  the string itself.
 */
public String toString() {
    return this;
}

equals() 方法

我們開啟 Object 類的原始碼, 可以看到 equals() 方法其實比較的是比較物件的地址。

/*
 * @param   obj   the reference object with which to compare.
 * @return  {@code true} if this object is the same as the obj
 *          argument; {@code false} otherwise.
 * @see     #hashCode()
 * @see     java.util.HashMap
 */
public boolean equals(Object obj) {
    return (this == obj);
}

但是我們發現 String 類比較的是 值的資訊,所以我們開啟看下 String類的原始碼,發現 String 重寫了equals() 方法

 /**
     * Compares this string to the specified object.  The result is {@code
     * true} if and only if the argument is not {@code null} and is a {@code
     * String} object that represents the same sequence of characters as this
     * object.
     *
     * @param  anObject
     *         The object to compare this {@code String} against
     *
     * @return  {@code true} if the given object represents a {@code String}
     *          equivalent to this string, {@code false} otherwise
     *
     * @see  #compareTo(String)
     * @see  #equalsIgnoreCase(String)
     */
    public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

hashCode() 方法

雜湊碼(hashCode)是按照一定的演算法由物件得到的一個數值,雜湊碼沒有規律。如果 A 和 B 是不同的物件,A.hashCode() 與 B.hashCode() 基本上不會相同。

從原始碼上看:

 /*
hashCode的常規協定是:
1.在java應用程式執行期間,在對同一物件多次呼叫hashCode()方法時,必須一致地返回相同的整數,
前提是將物件進行equals比較時所用的資訊沒有被修改。
從某一應用程式的一次執行到同一應用程式的另一次執行,該整數無需保持一致。
2.如果根據equals(object)方法,兩個物件是相等的,那麼對這兩個物件中的每個物件呼叫hashCode方法都必須生成相同的整數結果。
3.如果根據equals(java.lang.Object)方法,兩個物件不相等,
那麼對這兩個物件中的任一物件上呼叫hashCode()方法不要求一定生成不同的整數結果。
但是,程式設計師應該意識到,為不相等的物件生成不同整數結果可以提高雜湊表的效能。
*/
public native int hashCode();

例項

接收陣列資料

public class TestDemo {

	public static void main(String[] args) {
		Object obj = new int[]{1, 2, 3};	// 向上轉型
		System.out.println(obj);			// [[email protected]  物件地址前面有一個 [ , 表示為陣列
		
		if( obj instanceof int[] ){         // 判斷是否為 陣列物件
			int data[] = (int[]) obj;
			for (int i = 0; i < data.length; i++) {
				System.out.println(data[i]);	
			}
		}
	}
}

接收介面物件

interface A{
	public void fun();
}

class B extends Object implements A{
	@Override
	public void fun() {
		System.out.println("介面實現類");
	}
}

public class TestDemo {

	public static void main(String[] args) {
		A a = new B();	// 介面物件
		Object obj = a;	// 接收介面物件
		A t = (A) obj;	// 使用強制轉換向下轉型
		t.fun();		// 輸出結果:介面實現類
	}
}

物件克隆

物件克隆指的是物件的複製操作,進行克隆了之後的物件是另外一個物件,指向的記憶體地址是不一樣的,在 Object 類中提供有一個專門的克隆方法。定義如下:

protected native Object clone() throws CloneNotSupportedException;

會丟擲一個 CloneNotSupportedException 的異常,但是我們通過原始碼檢視 Cloneable 發現其定義是: public interface Cloneable { },是一個空的介面,所以介面為標識介面。

// 實現 Cloneable 標識介面
class Book implements Cloneable{
	private String title;
	private double price;
 
	public Book(String title, double price) {
		this.title = title;
		this.price = price;
	}
 
	public void setTitle(String title) {
		this.title = title;
	}
 
	@Override
	public String toString() {
		return "書名《" + this.title + "》價格:" + this.price + "元。";
	}
 
	/**
	 * 由於需要呼叫 protect 方法(本包、不同包的子類呼叫)
	 * 所以直接覆寫 Object 類中的 clone 方法
	 */
	@Override
	public Object clone() throws CloneNotSupportedException {
		return super.clone();
	}
}
 
public class SystemTest {
	public static void main(String[] args) throws Exception {
		Book booka = new Book("Java開發", 88.6);
		Book bookb = (Book) booka.clone();
		// 給 clone 的類修改內容
		bookb.setTitle("Android開發");
		System.out.println(booka);  // 書名《Java開發》價格:88.6元。
		System.out.println(bookb);  // 書名《Android開發》價格:88.6元。
	}
}