成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Java的Comparable接口的一個陷阱

開發 后端
Java的Comparable接口提供一個對實現了這個接口的對象列表進行排序的辦法。原始的排序對于簡單的對象來說具有意義,但是當我們面對復雜的面向對象的業務邏輯對象時,事情變得復雜的多。

Java的Comparable接口提供一個對實現了這個接口的對象列表進行排序的辦法。原始的排序對于簡單的對象來說具有意義,但是當我們面對復雜的面向對象的業務邏輯對象時,事情變得復雜的多。從業務經理的角度來看,一些交易對象的自然順序可能是按照交易的價值來排序的,但是從系統管理員的角度來看,這個排序的規則可能是交易的速度。所以在大多數情況下,并沒有明確的業務領域對象的自然排序規則。

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

  1. public class Company implements Comparable<Company> {  
  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(1729);  
  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.     }  

這個實現看起來沒問題,假設現在這個類提供的信息不夠使用,我們又創建了這個類的一個子類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(1931);  
  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.     }  

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

  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<CompanyDetails> set1 = CompaniesFactory.createCompanies1();  
  5. set1.add(c1);  
  6. set1.add(c2);  
  7.    
  8. Set<CompanyDetails> set2 = CompaniesFactory.createCompanies2();  
  9. set2.add(c1);  
  10. set2.add(c2);  
  11.    
  12. Assert.assertEquals(set1.size(), set2.size()); 

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

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

Java的Comparable接口的設計和使用的最佳實踐:

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

原文鏈接:http://my.oschina.net/jack230230/blog/56339

【編輯推薦】

  1. Apache CXF實戰之三:傳輸Java對象
  2. Java程序設計:圖形與多媒體處理
  3. Java集合框架總結:TreeSet類的排序問題
  4. Java圖形界面開發:高級Swing容器(三)
  5. Java理論與實踐: Web層的狀態復制
責任編輯:林師授 來源: OSCHINA
相關推薦

2009-09-02 14:59:35

Comparable接

2014-09-18 10:50:26

創業

2024-02-21 16:13:36

CNCF開源監控工具Prometheus

2021-05-21 07:26:15

DataSource接口數據庫

2020-09-22 07:50:23

API接口業務

2024-02-28 08:12:25

SSE接口代理

2021-04-14 07:33:02

Java函數式斷言

2025-01-13 00:00:10

Java排序接口

2022-06-21 14:44:38

接口數據脫敏

2024-11-07 10:55:26

2024-11-08 15:56:36

2019-11-20 23:44:29

接口數據加密數據安全

2022-05-16 10:45:22

Redis接口限流緩存

2020-04-20 17:15:32

Java開發代碼

2018-09-13 14:18:20

C語言Java程序員

2025-02-23 08:00:00

冪等性Java開發

2016-09-26 17:26:20

2022-01-06 14:59:53

Java框架magic-api

2024-08-28 10:33:56

2014-10-14 15:50:19

UIAndroid
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日韩a视频 | 欧美精品福利 | 国产精品久久久久久久久图文区 | 亚洲九九精品 | 欧美一级免费 | 国产精品日女人 | 亚洲午夜小视频 | 国产成人高清 | 性国产xxxx乳高跟 | 欧产日产国产精品v | 四虎成人免费视频 | 一区二区三区不卡视频 | 日韩一区二区三区在线播放 | 精品免费国产一区二区三区 | 成人免费看 | 国产精品一区二区在线播放 | 亚洲成av人片在线观看 | 亚洲毛片一区二区 | 日本精品一区二区三区在线观看视频 | 亚洲美乳中文字幕 | 精品久久久久久久久久久 | 精品国产乱码久久久久久蜜柚 | 国产精品高潮呻吟久久av黑人 | www.狠狠操| 欧美 视频 | 亚洲国产一区二区三区四区 | 欧美一区二区三区在线免费观看 | 欧美一区二区三区电影 | 日韩福利电影 | 一级欧美一级日韩片 | 一区二区三区久久 | 国产婷婷 | 国产女人第一次做爰毛片 | 国产免费一区二区三区 | 午夜精品一区二区三区在线视频 | 国产一区免费 | 国产一级大片 | 日日夜夜影院 | 伊人二区 | 国产综合久久久久久鬼色 | 日韩欧美精品一区 |