日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

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

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
Java的Comparable接口的一個陷阱

Java的Comparable接口提供一個對實現(xiàn)了這個接口的對象列表進行排序的辦法。原始的排序?qū)τ诤唵蔚膶ο髞碚f具有意義,但是當(dāng)我們面對復(fù)雜的面向?qū)ο蟮臉I(yè)務(wù)邏輯對象時,事情變得復(fù)雜的多。從業(yè)務(wù)經(jīng)理的角度來看,一些交易對象的自然順序可能是按照交易的價值來排序的,但是從系統(tǒng)管理員的角度來看,這個排序的規(guī)則可能是交易的速度。所以在大多數(shù)情況下,并沒有明確的業(yè)務(wù)領(lǐng)域?qū)ο蟮淖匀慌判蛞?guī)則。

創(chuàng)新互聯(lián)是一家專業(yè)提供赤壁企業(yè)網(wǎng)站建設(shè),專注與網(wǎng)站制作、網(wǎng)站建設(shè)、成都h5網(wǎng)站建設(shè)、小程序制作等業(yè)務(wù)。10年已為赤壁眾多企業(yè)、政府機構(gòu)等服務(wù)。創(chuàng)新互聯(lián)專業(yè)網(wǎng)站制作公司優(yōu)惠進行中。

假設(shè)我們找到了一個需要排序的類,比如說Campany。我們把公司的offical name作為主關(guān)鍵字,把id作為次要關(guān)鍵字。這個類的實現(xiàn)如下:

 
 
 
  1. public class Company implements Comparable {
  2.  
  3.     private final String id;
  4.     private final String officialName;
  5.  
  6.     public Company(final String id, final String officialName) {
  7.         this.id = id;
  8.         this.officialName = officialName;
  9.     }
  10.  
  11.     public String getId() {
  12.         return id;
  13.     }
  14.  
  15.     public String getOfficialName() {
  16.         return officialName;
  17.     }
  18.  
  19.     @Override
  20.     public int hashCode() {
  21.         HashCodeBuilder builder = new HashCodeBuilder(17, 29);
  22.         builder.append(this.getId());
  23.         builder.append(this.getOfficialName());
  24.         return builder.toHashCode();
  25.     }
  26.  
  27.     @Override
  28.     public boolean equals(final Object obj) {
  29.         if (obj == this) {
  30.             return true;
  31.         }
  32.         if (!(obj instanceof Company)) {
  33.             return false;
  34.         }
  35.         Company other = (Company) obj;
  36.         EqualsBuilder builder = new EqualsBuilder();
  37.         builder.append(this.getId(), other.getId());
  38.         builder.append(this.getOfficialName(), other.getOfficialName());
  39.         return builder.isEquals();
  40.     }
  41.  
  42.     @Override
  43.     public int compareTo(final Company obj) {
  44.         CompareToBuilder builder = new CompareToBuilder();
  45.         builder.append(this.getOfficialName(), obj.getOfficialName());
  46.         builder.append(this.getId(), obj.getId());
  47.         return builder.toComparison();
  48.     }
  49. }

這個實現(xiàn)看起來沒問題,假設(shè)現(xiàn)在這個類提供的信息不夠使用,我們又創(chuàng)建了這個類的一個子類CompanyDetail類用以擴展他。例如我們想以一個表的形式顯示公司的信息,我們就可以用這個類。

 
 
 
  1. public class CompanyDetails extends Company {
  2.  
  3.     private final String marketingName;
  4.     private final Double marketValue;
  5.  
  6.     public CompanyDetails(final String id, final String officialName, final String marketingName, final Double marketValue) {
  7.         super(id, officialName);
  8.         this.marketingName = marketingName;
  9.         this.marketValue = marketValue;
  10.     }
  11.  
  12.     public String getMarketingName() {
  13.         return marketingName;
  14.     }
  15.  
  16.     public Double getMarketValue() {
  17.         return marketValue;
  18.     }
  19.  
  20.     @Override
  21.     public int hashCode() {
  22.         HashCodeBuilder builder = new HashCodeBuilder(19, 31);
  23.         builder.appendSuper(super.hashCode());
  24.         builder.append(this.getMarketingName());
  25.         return builder.toHashCode();
  26.     }
  27.  
  28.     @Override
  29.     public boolean equals(final Object obj) {
  30.         if (obj == this) {
  31.             return true;
  32.         }
  33.         if (!(obj instanceof CompanyDetails)) {
  34.             return false;
  35.         }
  36.         CompanyDetails other = (CompanyDetails) obj;
  37.         EqualsBuilder builder = new EqualsBuilder();
  38.         builder.appendSuper(super.equals(obj));
  39.         builder.append(this.getMarketingName(), other.getMarketingName());
  40.         builder.append(this.getMarketValue(), other.getMarketValue());
  41.         return builder.isEquals();
  42.     }
  43. }

這個類的實現(xiàn)看起來還是沒什么問題,但是事實上是有問題的,我們可以寫一個test指出問題在哪里。當(dāng)我們沒有對父類的所有細節(jié)加以注意時,問題就來了。

 
 
 
  1. CompanyDetails c1 = new CompanyDetails("231412", "McDonalds Ltd", "McDonalds food factory", 120000.00);
  2. CompanyDetails c2 = new CompanyDetails("231412", "McDonalds Ltd", "McDonalds restaurants", 60000.00);
  3.  
  4. Set set1 = CompaniesFactory.createCompanies1();
  5. set1.add(c1);
  6. set1.add(c2);
  7.  
  8. Set set2 = CompaniesFactory.createCompanies2();
  9. set2.add(c1);
  10. set2.add(c2);
  11.  
  12. Assert.assertEquals(set1.size(), set2.size());

我們構(gòu)造了兩個set,但是結(jié)果是assert的結(jié)果是不相等。這是為什么?其中一個set是一個HashSet,他依賴對象的hashCode()和equals()方法,但是另一個是TreeSet,他只是依賴Comparable接口,而這個接口在子類中我們并沒有實現(xiàn)。在領(lǐng)域?qū)ο蟊粩U展的時候這是很常見的一個錯誤,但是更重要的是這是不好的編碼約定造成的。我們使用Apache Commons包中的builder來實現(xiàn)hashCode(),equals().和compareTo()方法。這些builder提供了appendSuper()方法,此方法指示了如何調(diào)用這些方法在父類中的實現(xiàn)。如果你看過Joshua Bloch 的Effective Java,你會發(fā)現(xiàn)這是錯誤的。如果我們在子類中添加成員變量,在不違反對稱規(guī)則的情況下,我們就不能正確的實現(xiàn)equals()方法和compareTo()方法。我們應(yīng)該使用組合的方式而不是繼承。如果我們使用組合的方式構(gòu)造CompanyDetails,對于Comparable接口來說沒有任何問題,因為我們沒有自動的實現(xiàn),而且在默認的情況允許不同的行為。而且我們也能滿足正確的equals()和hashCode()的需求。

這篇文章提到的問題非常普遍,但是經(jīng)常被忽視。Comparable接口的問題實際是由于不好的約定和對使用的接口需求的錯誤理解造成的。作為一個Java開發(fā)人員或架構(gòu)師,你應(yīng)該特別注意這樣的事情,并遵守良好的編碼習(xí)慣和做法。 越大的項目,這種問題就越顯得重要。這里我總結(jié)了一個使用Comparable接口的最佳實踐,可以避免這個錯誤。

Java的Comparable接口的設(shè)計和使用的最佳實踐:

  • 了解你需要創(chuàng)建的領(lǐng)域?qū)ο?,如果對象沒有明確的排序規(guī)則,請不要實現(xiàn)Comparable接口。
  • 更多的使用Comparator而不是Comparable,Comparator在更多的業(yè)務(wù)使用方式時要顯得更為實用。
  • 如果你需要創(chuàng)建依賴Comparable接口的接口或者庫,如果可能的話你提供自己的Comparator實現(xiàn),否則就寫一個良好的文檔指明在你的接口實現(xiàn)類中如何實現(xiàn)。
  • 遵守良好的編碼習(xí)慣和做法。Effective Java是很好的推薦。

網(wǎng)站名稱:Java的Comparable接口的一個陷阱
鏈接地址:http://m.5511xx.com/article/dphpscp.html