日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢(xún)
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷(xiāo)解決方案
"一致性相等"的陷阱

關(guān)于Object類(lèi)中的equals()方法與Comparable接口中的compareTo()方法之間有何種關(guān)聯(lián),之前還真沒(méi)考慮過(guò)。通過(guò)java.net看到此文之后,收獲了一點(diǎn)兒新知識(shí),希望大家也能如此。

創(chuàng)新互聯(lián)建站-專(zhuān)業(yè)網(wǎng)站定制、快速模板網(wǎng)站建設(shè)、高性?xún)r(jià)比霍爾果斯網(wǎng)站開(kāi)發(fā)、企業(yè)建站全套包干低至880元,成熟完善的模板庫(kù),直接使用。一站式霍爾果斯網(wǎng)站制作公司更省心,省錢(qián),快速模板網(wǎng)站建設(shè)找我們,業(yè)務(wù)覆蓋霍爾果斯地區(qū)。費(fèi)用合理售后完善,10年實(shí)體公司更值得信賴(lài)。

方法equals()與Comparable接口中的compareTo()方法是Java中最基本的兩個(gè)方法之一,然而它們的定義卻圍繞著"與相等一致"這一有趣的概念。

equals()方法

Java中的equals()方法既明確,又模糊。Java清楚地定義了如何準(zhǔn)確地檢驗(yàn)一個(gè)equals()方法是可用的。一個(gè)恰當(dāng)?shù)膃quals()方法必須是自反的,對(duì)稱(chēng)的,可傳遞的,一致的,并能處理null引用。

然而equals()方法又是不清晰的。Javadoc說(shuō)到,該方法指定了其它對(duì)象是"等于"這個(gè)對(duì)象的。注意,"等于"是放在引號(hào)中的。此處的關(guān)鍵就是,它沒(méi)有定義如何去判定這種相等性。

·對(duì)象的一致性(==)默認(rèn)是繼承自O(shè)bject類(lèi)

·對(duì)象的整體可觀測(cè)的狀態(tài),例如,若兩個(gè)對(duì)象是相等的,那么在應(yīng)用的其它部分可以用一個(gè)對(duì)象去替代另一個(gè)對(duì)象。

·對(duì)象信息中的某些部分,如ID,使得檢驗(yàn)對(duì)象相等性在邏輯上是有意義的。

compareTo()方法

Comparable接口定義了可比較性的概念。Javadoc指出compareTo()方法"強(qiáng)制設(shè)定了每個(gè)實(shí)現(xiàn)了該接口的類(lèi)的對(duì)象的全部順序"。

實(shí)現(xiàn)了Comparable接口的類(lèi)有一個(gè)天然的排序,這可便于存儲(chǔ),也能在不使用單獨(dú)的Comparator的情況下,用于像TreeSet和TreeMap這樣的集合對(duì)象。

該接口的定義明晰,它要求其實(shí)現(xiàn)必須確保對(duì)稱(chēng)性與傳遞性,就像equals()方法那樣。

一致性/非一致性相等

Comparable接口有如下描述:

類(lèi)C的天然排序意味著要與equals()方法保持一致,只有當(dāng)且僅當(dāng)e1.compareTo(e2) == 0與e1.equals(e2)有相同的布爾值。

基本上,這就要求由compareTo()定義的相等性與equals()方法定義的相等性具有相同的概念(除去有null的情況)。乍一看,該要求很簡(jiǎn)單,但實(shí)際上它有其復(fù)雜性,后面將會(huì)討論到。

當(dāng)考慮到操作符重載時(shí),這種定義就特別有用。若我們假設(shè)有一種類(lèi)Java語(yǔ)言,在這種語(yǔ)言中,==并不表示對(duì)象的同一性,而是通過(guò)方法去進(jìn)行比較,大于/小于操作符也是如此,問(wèn)題是調(diào)什么樣的方法。在類(lèi)Java語(yǔ)言中大于/小于天然地就要基于compareTo()方法,而==則要調(diào)用equals()方法。

 
 
 
  1. // our new Java-like language  
  2. if (a < b) return "Less";      // translation ignoring nulls: if (a.compareTo(b) < 0)  
  3. if (a > b) return "Greater";   // translation ignoring nulls: if (a.compareTo(b) > 0)  
  4. if (a == b) return "Equal";    // translation ignoring nulls: if (a.equals(b))  
  5. throw new Exception("Impossible assuming no nulls?"); 

但如果compareTo()方法不是"一致性相等",那么上述代碼將會(huì)拋出異常,因?yàn)楫?dāng)a.equals(b)為false時(shí),a.compareTo(b)會(huì)返回0。

在集合,如TreeMap,中還會(huì)發(fā)生其它問(wèn)題:

 
 
 
  1. // Foo class is "inconsistent with equals"  
  2. assert foo1.equals(foo2) == false;  
  3. assert foo1.compareTo(foo2) == 0;  
  4.    
  5. TreeMap map =   
  6. map.put(foo1, "a");  
  7. map.put(foo2, "b"); 

當(dāng)使用equals()方法時(shí),這兩個(gè)對(duì)象不相等,但使用compareTo()時(shí),它們卻相等。在這種情況下,該Map的元素個(gè)數(shù)將為1,而非0。

由于這些"一致性相等"的問(wèn)題,Javadoc說(shuō)道"強(qiáng)烈建議(盡管并不要求)天然排序規(guī)則要與equals()方法保持一致"。

JDK中的許多類(lèi)為了符合"一致性相等"這一規(guī)范而實(shí)現(xiàn)了Comparable接口。這些類(lèi)包括Byte,Short,Integer,Long,Character和String。

還有些更有趣的類(lèi):

BigDecimal--肯定是"非一致性相等",比如4.00與4.0不一致,但進(jìn)行比較時(shí),認(rèn)為它們是一樣的。

Double/Float--該類(lèi)顯式地提供了排序規(guī)則,并為正零和負(fù)零,以及NaN都提供了相等性檢查,以確保它的compareTo()方法符合"一致性相等"。

CharSet--該類(lèi)基于ID或名稱(chēng)。equals()方法對(duì)待字段串是大小寫(xiě)敏感的,但compareTo()方法卻不這樣。雖然名稱(chēng)一般會(huì)符合某種標(biāo)準(zhǔn),但這是一種值得懷疑的"一致性"。

*Buffer(nio)--該簇類(lèi)的比較基于緩沖存放的內(nèi)容,在我的測(cè)試中equals()和compareTo()是"一致的"。

Rdn(ldap)--該類(lèi)的比較基于狀態(tài)的標(biāo)準(zhǔn)化格式,因此也是"一致性相等"。

ObjectStreamField(序列化)--該類(lèi)的比較基于名稱(chēng),但會(huì)首先對(duì)基本數(shù)據(jù)類(lèi)型進(jìn)行排序。因?yàn)闆](méi)有覆蓋equals()方法,所以是"非一致性相等"。

 ...

注意:對(duì)于大多數(shù)的例子,我都不得不查看其源代碼或編寫(xiě)測(cè)試程序以確定該類(lèi)是不是符合"一致性相等"。這兒有一個(gè)不錯(cuò)地清理Javadoc和檢驗(yàn)UUID equals()方法的Adopt-a-JDK任務(wù)。

JSR-310

一直看到許多關(guān)于BigDecimal的問(wèn)題,已有計(jì)劃將JSR-310中的類(lèi)改造成"一致性相等",最近的一些帖子顯示這將造成多么大的爭(zhēng)議。

基本上,為某些類(lèi)定義equals()和compareTo()看起來(lái)很容易。LocalDate表示某單一日歷系統(tǒng)中的某個(gè)日期,所以它有一個(gè)顯而易見(jiàn)的排序算法和相等規(guī)則。LocalTime則表示某個(gè)時(shí)刻,所以它也有一個(gè)明顯的排序算法和相等規(guī)則。Instant表示時(shí)間線上的某個(gè)時(shí)刻,那么它的排序與相等也是顯見(jiàn)的。

但在其它的情況下,這就不是那么顯而易見(jiàn)了??紤]這樣一個(gè)類(lèi)OffsetDateTime:

 
 
 
  1. dt1 = OffsetDateTime.parse("2012-11-05T06:00+01:00");  
  2. dt2 = OffsetDateTime.parse("2012-11-05T07:00+02:00"); 

這樣的兩個(gè)日期-時(shí)刻對(duì)象代表時(shí)間線上一個(gè)相同的時(shí)刻點(diǎn),但它們有不同的本地時(shí),而且相對(duì)的UTC/格林威治時(shí)間的偏移量也不相同。

那么就有一個(gè)問(wèn)題要留給讀者們...你更傾向于如下哪種觀點(diǎn)...

1. dt1不等于dt2,compareTo()分別比較本地時(shí)與偏移量,使用"一致性相等"(使用獨(dú)立的Comparator基于時(shí)刻對(duì)其進(jìn)行排序)。

2. dt1不等于dt2,compareTo()基于時(shí)間線的上時(shí)刻點(diǎn),使用"非一致性相等"。

3. dt1等于dt2,compareTo()基于時(shí)間線的上時(shí)刻點(diǎn),使用"一致性相等"。

4. dt1等于dt2,且不實(shí)現(xiàn)Comparable接口。

5. dt1不等于dt2,且不實(shí)現(xiàn)Comparable接口。

我個(gè)人更傾向于讓dt1.equals(dt2)返回true這種方案,但我仍持開(kāi)放態(tài)度。

順便地,也可以將這個(gè)問(wèn)題提給BigDecimal,如果你能修改這個(gè)類(lèi),使其符合"一致性相等",你會(huì)修改它的equals()方法,還是compareTo()方法?


分享文章:"一致性相等"的陷阱
網(wǎng)站URL:http://www.dlmjj.cn/article/djpjdjo.html