自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Java的Comparable接口的一個(gè)陷阱

開發(fā) 后端
Java的Comparable接口提供一個(gè)對(duì)實(shí)現(xiàn)了這個(gè)接口的對(duì)象列表進(jìn)行排序的辦法。原始的排序?qū)τ诤?jiǎn)單的對(duì)象來(lái)說(shuō)具有意義,但是當(dāng)我們面對(duì)復(fù)雜的面向?qū)ο蟮臉I(yè)務(wù)邏輯對(duì)象時(shí),事情變得復(fù)雜的多。

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

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

  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.     }  

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

  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.     }  

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

  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()); 

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

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

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

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

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

【編輯推薦】

  1. Apache CXF實(shí)戰(zhàn)之三:傳輸Java對(duì)象
  2. Java程序設(shè)計(jì):圖形與多媒體處理
  3. Java集合框架總結(jié):TreeSet類的排序問(wèn)題
  4. Java圖形界面開發(fā):高級(jí)Swing容器(三)
  5. Java理論與實(shí)踐: Web層的狀態(tài)復(fù)制
責(zé)任編輯:林師授 來(lái)源: OSCHINA
相關(guān)推薦

2009-09-02 14:59:35

Comparable接

2014-09-18 10:50:26

創(chuàng)業(yè)

2024-02-21 16:13:36

CNCF開源監(jiān)控工具Prometheus

2021-05-21 07:26:15

DataSource接口數(shù)據(jù)庫(kù)

2020-09-22 07:50:23

API接口業(yè)務(wù)

2024-02-28 08:12:25

SSE接口代理

2021-04-14 07:33:02

Java函數(shù)式斷言

2025-01-13 00:00:10

Java排序接口

2024-11-08 15:56:36

2022-06-21 14:44:38

接口數(shù)據(jù)脫敏

2024-11-07 10:55:26

2019-11-20 23:44:29

接口數(shù)據(jù)加密數(shù)據(jù)安全

2022-05-16 10:45:22

Redis接口限流緩存

2018-09-13 14:18:20

C語(yǔ)言Java程序員

2020-04-20 17:15:32

Java開發(fā)代碼

2025-02-23 08:00:00

冪等性Java開發(fā)

2016-09-26 17:26:20

2022-01-06 14:59:53

Java框架magic-api

2024-08-28 10:33:56

2022-12-12 08:14:47

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)