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元。
}
}