??????? 相對于C++,Java并沒有重載操作符,所以對于非基本類型都需要使用equals方法比較相等性.Object提供了equals方法比較兩個對象,但對于用戶自定義類而言O(shè)bject提供的版本僅僅比較兩個對象的引用是否相同,這在很多情況下并不符合程序的意思,例如JDK中就重寫了很多equals方法覆蓋Object的版本,以達到庫文件編寫者真正要表達的相等性比較方式.
對于用戶自定義類而言,如果需要編寫equals方法,可能存在下面幾個問題:
1.是否只有兩個對象引用相同才相等?
2.如果引用了不同對象,是否比較其中數(shù)據(jù)來決定是否相等?
3.當比較超類和子類時又會引出新的問題:
3a.超類和子類誰應(yīng)該具有相等性意識
3b.如果超類具有相等性意識,是否應(yīng)該在繼承層次中是唯一的,子類應(yīng)當遵循超類的相等性比較方案
3.c.或者為子類單獨提供相等性比較方法
3.d.超類和子類同時存在相等性比較方法
3.e.當超類和子類相比較時,是否因為其所屬類不同就直接返回false,或者并不介意其所屬類而進入數(shù)據(jù)比較階段,這意味著兩個不一樣的類型或許相等
3.f.在超類和子類的數(shù)據(jù)比較中,假設(shè)子類擴展了數(shù)據(jù),是否忽略子類的擴展部分,如果不忽略那超類和子類的比較便是不成立的,因為永遠為false.
3.g.或者為不同的子類提供不同的方案,有的子類調(diào)用超類方法,有的子類調(diào)用自己的方法,有的子類調(diào)用Object的方法.
4.在數(shù)據(jù)比較中比較雙方在同一個數(shù)據(jù)域都為null,應(yīng)該表示為相等還是不相等.
以上問題需要在類的設(shè)計時便得到解答,設(shè)計equals()方法還需要同時滿足Java的語言規(guī)范
Java語言規(guī)范要求equals方法具有下列特征
1.自反性,對于任何非空引用x, x.equals(x);都應(yīng)該返回true
2.對稱性,對于任何引用x和y, x.eqauls(y)返回true, y.equals(true)也應(yīng)該返回true
3.傳遞性,對于任何引用,x,y和z,x.eqauls(y)返回true,y.eqauls(z)返回true,x.eqauls(z)也應(yīng)該返回true
4.一致性,如果x和y引用的對象沒有發(fā)生變化,反復(fù)調(diào)用x.eqauls(y)應(yīng)該返回相同的結(jié)果
5.對于任何非空引用,x.eqauls(null)應(yīng)該返回false
定義一個類
public class Person {
??????? String name;
??????? int height;
??????? double weight;
??????? int ID;
}
繼承了來自O(shè)bject的equals方法
Person mike = new Person("Mike", 6.5, 150);
Person gomez = new Person("Gomez", 5.9, 100);
if( mike == gomez )
??????? System.out.println("調(diào)用Object的equals方法比較,并非相同應(yīng)用返回false");
Person friendOfMike= gomez;
if(friendOfMike == gomez)
??????? System.out.println("相同的引用,返回true");
Person類隱式的繼承自O(shè)bject類,Object.equals()的實現(xiàn)類似與這種
public boolean equals(Object param)
{
??????? return this == param;
}
只要引用指向內(nèi)存中相同的一塊區(qū)域則為真,否則為false
public boolean equals(Object o)
{
??????? if(o == null) ? ? ? ? //確保參數(shù)不為空
?????????????? return false;
??????? if(super.equals(o)) ? ? ?? // 引用相同肯定相等
?????? ? ? ? ?? return true;
??????? Person guy = (Person) o;
??????? //開始比較數(shù)據(jù)域,數(shù)據(jù)全部相等返回true
??????? if(name.equals(guy.name) && height == guy.height && weight == guy.weight)
??????????????? return true;
??????? return false;
}
沒有繼承關(guān)系的情況下相對比較簡單,只需要簡單的決定比較引用還是比較數(shù)據(jù)就可以了,加入了繼承關(guān)系以后情況稍微多了些變化
class Worker extends Person {
??????? String job;
}
聲明幾個Worker變量
Worker []operators = new Worker[3];
operators[0] = new Worker("Mike", 6.5, 150,"operation");
operators[1] = new Worker("Gomez", 6.0, 145,"operation");
operators[2] = new Worker("Huan", 6.7, 138,"operation");
如果為Worker編寫equals方法,程序想要表達的意思是比較是否是同一個人,作為Person的子類,我們希望他也能和Person對象比較,并且比較引用相同直接返回true,否則比較數(shù)據(jù)域,當數(shù)據(jù)域相同時視作同一個人,返回true.我們不關(guān)心比較的雙方是什么類型(當然至少是Person或Worker中的任何一種),Worker擴展的數(shù)據(jù)部分只在比較兩邊都是Worker對象是才需要比較.
if(operators[0].equals(mike))
??????? System.out.println("雖然引用不同,但是值完全相同所以視作同一人,注意Worker對象新增的job域沒有參與比較");
if(operators[1].equals(gomez))
??????? System.out.println("只是名字相同,返回了false");
if(operators[0].equals(operators[2]))
??????? System.out.println("兩個Worker比較將比較新增job域的內(nèi)容");
為了實現(xiàn)以上比較的正確運行,為Worker類實現(xiàn)equals()方法
public boolean equals(Object o)
{
??????? if(!super.equals(o))
??????????????? return false; //參數(shù)為空或數(shù)據(jù)對比失敗
??????? if(getClass() == o.getClass()){
??????????????? Worker com = (Worker)o;
?????? ? ? ? ?? if(job.equals(com.job)) //如果同位Worker對象還需要對比新增的job域
????? ? ? ? ? ? ? ? ? ? return true;
?????? ? ? ? ?? else
??????????????????????? return false;
??????? }
??????? return true;
}
還有一種可能便是不論比較雙方對象的所屬類是什么,只調(diào)用超類的equals方法,這樣做的意義在我們例子里就是工廠或許不清楚每個工人的實際身份,也不關(guān)心,可以確定是否是同一個人的數(shù)據(jù)全部儲存在了Person類中,或者說,Person類已經(jīng)有了足夠的信息來確定equals方法的比較雙方是否是同一個人了,這種情況就是子類Wroker沒有相等性意識,而超類Person具有相等性意識.
if(operators[0].equals(mike))
??????? System.out.println("雖然引用不同,但是值完全相同所以視作同一人");
if(operators[1].equals(gomez))
??????? System.out.println("只是名字相同,返回了false");
if(operators[0].equals(operators[2]))
??????? System.out.println("兩個Worker比較,依然只比較Person類所定義的數(shù)據(jù)域");
從新改寫Wroker的equals方法
public boolean equals(Object o)
{
??????? if(!super.equals(o))
??????????????? return false; //參數(shù)為空或數(shù)據(jù)對比失敗
??????? return true;
}
從新改寫Person的equals方法
public boolean equals(Object o)
{
??????? if(o == null) //確保參數(shù)不為空
??????????????? return false;
??????? if(super.equals(o)) //引用相同肯定相等
??????????????? return true;
??????? if(!(o instanceof Person))
??????????????? return false; //如果參數(shù)o不是從Person派生出去的子類則返回false
??????? Person guy = (Person) o;
??????? //開始比較數(shù)據(jù)域,數(shù)據(jù)全部相等返回true
??????? if(name.equals(guy.name) && height == guy.height && weight == guy.weight)
??????????????? return true;
??????? return false;
}
經(jīng)過檢驗,以上程序符合Java語言規(guī)范提出的5項equals()方法的特征.