[Java]重新編寫Object類中的方法(zt)

來源:互聯網
上載者:User
Object類是所有類的超類,也就是說,Java中的每一個類都是由Object擴充而來的.因而每當你建立一個對象,它都將擁有Object類中的全部方法.讓我們先來看看java.lang.Object的中的主要方法有哪些:
public class Object{
//公用建構函式
public Object();
//公用執行個體方法
public boolean equals(Object obj);
public native int hashCode();
public final native Class getClass();
public String toString();
public final native void notify();
public final native void notifyAll();
public final void wait() throws InterruptedException;
public final native void wait(long timeout) throws InterruptedException;
public final void wait(long timeout, int nanos) throws InterruptedException;
//保護執行個體方法
protected native Object clone();
protected void finalize() throws Throwable; }
方法equals測試的是兩個對象是否相等,方法clone進行對象拷貝,方法getClass返回和當前對象相關的Class對象,方法notify,notifyall,wait都是用來對給定對象進行線程同步的.
然而Object類所提供的只是一些基本的方法,我們在編寫自己的類時經常需要覆蓋這些方法,一方面是加強功能,另一方面也是為了適應當前的情況.這就引出了本文的主題——
如何編寫自己的equals方法
首先要明確一個問題,Object類中的equals方法是怎樣判斷兩個對象是否相等的呢?讓我們來看看它的原始碼:
public boolean equals(Object obj)
{
return (this == obj);
}

不難看出,它僅僅判斷了兩個對象的引用是否相等,這在很多情況下並沒有太大的實際意義.比如,我們需要一個比較兩個字串是否相等,在String類中就覆蓋了這個方法.標準的java類庫中有超過150個equals方法的實現.然而java語言規範要求equals方法具有以下性質:
自反性:對於任何非Null 參考x, x.equals(x)返回true.
對稱性:對於任何非Null 參考x和y, 若且唯若y.equals(x)返回true時,x.equals(y)返回true.
傳遞性:對於任何引用x,y和z,如果x.equals(y)返回true並且y.equals(z)也返回true,那麼x.equals(z)應該返回true.
一致性:如果x和y引用的對象沒有改變,那麼x.equals(y)的重複調用應該返回同一結果.
對於任何非Null 參考x, x.equals(null)應該返回false.
這5條規則顯示良好的邏輯性,想要寫好自己的equals方法,必須滿足它們.那麼如何才能做到這些規則呢?
假設當前equals方法傳進來的參數名為otherObject,
測試this是否與otherObject相等.
測試otherObject是否為null,如果是,一定要返回false.
測試this通otherObject是否同屬於一個類.這是為了滿足規則2.
把otherObject強制轉換為另一個變數(這裡稱為other):Classname other = (Classname) otherObject.然後比較所有的欄位.使用 == 比較基本類型欄位,使用equals方法比較對象欄位.如果所有的欄位都匹配返回true,否則返回false.
下面舉一個簡單的例子:
class TestEqual{
int number;
String s;
public boolean equals(Object otherObject){
//首先看看這兩個對象引用是否相等
if (this == otherObject)
return true;
//這是為了滿足規則5
if(otherObject == null)
return false;
//如果兩個對象所屬類型不同,它們不可能相等
if(getClass() != otherObject.getClass())
return false;
TestEqual other = (TestEqual)otherObject;
//比較所有欄位
return s.equals(otherObject.s) & number == otherObject.number;
}
}
這個例子雖然很簡單,但卻清晰地反映出了以上所說的要點.
還有一個需要注意的地方是,在子類中,首先要調用超類的equals方法,如果這項測試無法通過,那麼兩個對象不可能相等.也就是:
if(!super.equals(otherObject)) return false;

到這裡相信大家已經對編寫自己的equals方法有了一定的認識,只要在平時寫程式的時候多注意一下,寫好它並不難.
再來看看本文的第二大主題:

如何編寫自己的clone方法
類似equals方法,我們先來討論一下Object的clone方法效果是怎樣的.不過在此之前,有個問題要提一下,所有使用clone方法的類,不論是繼承Object.clone()還是覆蓋它,都必須實現一個名為cloneable的介面.如果你開啟java類庫查一下,會發現這個介面裡什麼也沒有,它僅僅是表明某個類具有被clone的能力.
用一個例子來研究一下Object.clone()的複製效果:
public class TestClone1 implements Cloneable{
int count;
TestClone1 next;
public TestClone1(int count) {
this.count=count;
if(count>0)
next=new TestClone1(count-1);
}
void add(){
count++;
if(next!=null)
next.count++;
}
public String toString(){
String s=String.valueOf(count)+" ";
if(next!=null)
s+=next.toString();
return s;
}
public Object clone(){
Object o=null;
//如果沒有實現cloneable,將會拋出CloneNotSupported異常
try{
o=super.clone();
}
catch(CloneNotSupportedException e){
System.err.println("cannot clone");
}
return o;
}
public static void main(String[] args){
TestClone1 t=new TestClone1(1);
System.out.println("t="+t);
TestClone1 t1=(TestClone1)t.clone();
System.out.println("t1="+t1);
t.add();
System.out.println("after addedt t="+t+"t1="+t1)
}
}

在這個例子中建立t相當於兩個相連的TestClone1執行個體,而在調用了t的add方法之後,意想不到的結果出現了:
t=1 0
t1=1 0
after added
t t=2 1
t1=1 1
t1也發生了改變,這點也許有些出乎你的意料.實際上Object.clone()進行的複製有著"bitwise"原則,也就是逐位複製.對於一個對象中定義的對象,它只是簡單的複製這個對象的引用.這也就是常說的淺層拷貝(shallow copy),明白了這一點,想要執行深層拷貝(deep copy)也就不難了.
只需要在TestClone1 t1=(TestClone1)t.clone();後面加上t1.next=(TestClone1)t.next.clone();就能得到:
t=1 0
t1=1 0
after added
t t=2 1
t1=1 0
這個正確的結果.
接下來要介紹的是,如何控制clone能力.從前面可以知道,clone()是protected的,你必須覆蓋並實現cloneable介面並處理必要的異常才能使用它.這樣,你在設計自己的類時,有以下幾種風格來控制clone能力:
不理會clone(),也就是在你的類中不涉及任何有關clone()的內容,如果有人想實現clone功能,必須寫一個子類並完成剛才所說的要求.這適合於Object.clone()可以勝任複製你的類中全部欄位的情況.
支援clone().你在你的類中實現cloneable介面並且覆蓋clone方法以及捕獲相應的異常.
有條件的支援clone().這種情況有些特殊,也就是你的類中儲存著一些可能不能被複製的對象的引用(這裡是指它們沒有實現cloneable).這時候你只是在clone()中複製所有這些對象,如果遇到異常,拋出所有這些異常給使用你的類的人.舉個例子,假設你在寫一個類似於ArrayList的類,你不知道別人會在把什麼樣的對象儲存在你的ArrayList裡,所以你也不知道他們是否能夠被複製.
不實現cloneable介面但覆蓋clone方法為protected.這樣你雖然讓你的類不能被複製,但卻提供了正確的clone方法,這樣如果有人想複製你的類,寫一個子類實現cloneable介面就行了.
不實現cloneable介面並覆蓋clone方法直接拋出異常來防止你的類被複製.不過這並不是根本的解決方案,只能對付那些直接調用你的clone方法或是在子類中調用super.clone()的人.
使用final修飾你的類來防止你的類被複製.如果你的超類中有覆蓋clone方法的,再重新覆蓋clone方法並直接拋出異常.這也是最徹底的辦法.
希望通過本文的介紹,能夠使大家對Object類有個大概的瞭解,編寫好自己的equals和clone方法,以適應不同的需要. 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.