聲明:原創作品,轉載時請注明文章來自SAP師太技術博客( 博/客/園www.cnblogs.com):m.survivalescaperooms.com/jiangzhengjun,并以超鏈接形式標明文章原始出處,否則將追究法律責任!原文鏈接:http://m.survivalescaperooms.com/jiangzhengjun/p/4255581.html 第三章 對所有對象都通用的方法 8、 覆蓋equals時請遵守通用約定 如果類具有自己特定的“邏輯相等”概念(不同于對象等同概念),而且超類還沒有覆蓋equals以實現期望的行為,這時我們就需要覆蓋equals方法,這通常屬于“值類”的情形,例如Integer或者是Data,程序員在利用equals方法來比較值對象的引用時,希望知道它們在邏輯上是否相等,而不是想了解它們是否指向同一個對象。
在覆蓋equals方法時,你必須要遵守它的通用約定。下面是約定的內容,來自Object的規范:
l自反性:對于任何非null的引用值x,x.equals(x)必須返回true。如果自已不等于自己的話,將其放入集合中后,該集合的contains方法將告訴你,集合中不包括你剛添加的實例。
l對稱性:對于任何非null的引用值x和y,當且僅當y.equals(x)返回true時,x.equals(y)必須返回true。這就要求不同類的實例如果在邏輯值相同的情況下,要求這兩個實例所對應的類的equals方法比較邏輯要相同,不然的話,對稱性將不再滿足。
l傳遞性:對于任何非null的引用值x、y和z,如果x.equals(y)返回true,并且y.equals(z)也返回true,那么x.equals(z)也必須返回true。
l一致性:對于任何非null的引用值x和y,只要equals的比較操作在對象中所用的信息沒有被修改,多次調用x.equals(y)就會一致地返回true,或者一致地返回false。
l非空性:對于任何非null的引用值x,x.equals(null)必須返回false。
實現高質量的equals方法:
1、使用==操作符檢查“參數是否為這個對象的引用”。如果是,則返回true,這只不過是一種性能優化,如果比較操作有可能很昂貴,就值得這么做。
2、使用instanceof操作符檢查“參數是否為正確的類型”。如果不是,則返回false。一般說來所謂“正確的類型”是指定equals所在的那個類。有些情況下,是指該類所實現的某個接口。如果類實現的接口改進了equals約定,允許在實現了該接口的類之間進行比較,那么就使用接口。集合接口如Set、List、Map和Map.Entry具有這樣的特性。注,這步會過濾掉null,因為null instanceof XX一定會返回false。另外,要注意的是,如果你只與自己本身類型的類相比,則可以使用if(getClass() == obj.getClass())來限制為同一個類比較而不希望是父類或其子類(思想來源于《PRactice Java》)。
3、把參數轉換成正確的類型。因為轉換之前進行過instanceof測試,所以確保會成功。
4、對于該類中的每個“關鍵”域,檢查參數中的域是否與該對象中對應的域相匹配。如果這些測試全部成功,則返回true,否則返回false。
對于既不是float也不是double類型的基本類型域,可以使用==操作符進行比較;對于對象引用域,可以遞歸地調用equals方法;對于float域,可以使用Float.compare方法;對于double域,則使用Double.compare。對于數組域,則要把以上這些指導原則應用到每個元素上,如果數組域中的每個元素都需要比較的話,可以使用1.5版本中發行的Arrays.equals方法。
對于float和double域進行特殊的處理是有必要的,因為存在著Float.NaN、-0.0f以及類似的double常量,詳細信息請參考Float.equals的文檔,看看Float.equals源碼與文檔描述:
publicbooleanequals(Object obj) {
return(objinstanceofFloat)
&& (floatToIntBits(((Float) obj).value) == floatToIntBits(value));
}
在比較是否相等時使用是floatToIntBits(float)方法,即將浮點的二進制位看作是整型位后比較的。注意,在大多數情況下,對于Float類的兩個實例f1和f2,讓f1.equals(f2)的值為true的條件是當且僅當f1.floatValue() == f2.floatValue()的值也為true。但是也有下列兩種例外:
l如果f1和f2都表示Float.NaN(規定Float.NaN = 0x7fc00000),那么即使Float.NaN = = Float.NaN的值為false,equals方法也將返回true(因為他們所對應的整型位是相同的)。
l如果f1表示+0.0f,而f2表示-0.0f,或相反的情況,則equal測試返回的值是false(因為他們所對應的整型位是不同的),即使0.0f = = -0.0f的值為true也是如此。
另外,來看看Float.compare的源碼:
publicstaticintcompare(floatf1,floatf2) {
if(f1 < f2)
return-1; // Neithervalis NaN, thisVal is smaller
if(f1 > f2)
return1; // Neithervalis NaN, thisVal is larger
intthisBits = Float.floatToIntBits(f1);
intanotherBits = Float.floatToIntBits(f2);
return(thisBits == anotherBits ? 0 : // Values are equal
(thisBits < anotherBits ? -1 : // (-0.0, 0.0) or (!NaN, NaN)
1)); // (0.0, -0.0) or (NaN, !NaN)
}
compare是從數字上比較兩個Float對象。在應用到基本float值時,有兩種方法來比較執行此方法產生的值與執行Java語言的數字比較運算符(<、<=、==和>= >)產生的那些值之間的區別:
l該方法認為Float.NaN將等于其自身,且大于其他所有float值(包括Float.POSITIVE_INFINITY)。
l該方法認為0.0f將大于-0.0f。
請記住,如果是通過Java語言的數字比較運算符(<、<=、==和>= >)而不是compare方法來比較時,只要其中有一個操作為Float.NaN,那么比較結果就是false。
對象引用域的值為null是有可能的,所以,為了避免可能導致的空指針異常,則使用下面的作法:
新聞熱點
疑難解答