程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Delphi >> equals方法實現小記

equals方法實現小記

編輯:Delphi

  最近做項目,在一次寫equals方法時突然悟出了一些心得,小記之,以備後用。在《Effective Java(第二版)》的Item7中提出我們要盡量避免重新equals方法,他同時也列舉了幾種我們不需要實現equals方法的情況:
1)類的每個實例從本質上來說是唯一的,如Thread類的實例。
2)我們並不會用到該類的equals方法,如Random類,雖然可以比較兩個Random的實例,以判斷兩個實例是否可以產生相同的隨機數,設計者認為這樣的需求用到的場合很少,因而就沒有重寫equals方法。
3)父類已經實現了equals方法,並且父類實現方式和子類實現方式是一樣的,如大部分的Set實現的equals方法使用AbstractSet類提供的equals方法,List實現則使用AbstractList,Map實現使用AbstractMap的。
4)一個private類或package-private類,我們自己可以確保我們不會使用到它們的equals方法。
同時書也提出一般只有值類型的類才需要實現equals方法,像Date、Integer、Order(作為bean來使用)等。
另外,我們在實現equals方法是也要遵循以下幾個原則:
1)自反性(reflexive):x.equals(x)==true
2)對稱性(symmetric):x.equals(y)==y.equals(x)
3)傳遞性(transitive):若x.equals(y)==true, y.equals(z)==true,則x.equals(z)==true。
4)一致性(consistent):多次調用x.equals(y)的結果應該是一樣的。
5)對任何非null實例x,x.equals(null)==false。

根據這些特性,我們可以寫出如下代碼:
 1 public class Customer implements Serializable {
 2     private static final long serialVersionUID = 1L;
 3    
 4     private String id;
 5     private String name;
 6     private String role;
 7    
 8     @Override
 9     public boolean equals(Object obj) {
10         if(obj == null) {
11             return false;
12         }
13        
14         if(this == obj) {
15             return true;
16         }
17        
18         if(!(obj instanceof Customer)) {
19             return false;
20         }
21        
22         Customer other = (Customer)obj;
23         return (ObjectUtils.equals(id, other.id) &&
24                 ObjectUtils.equals(name, other.name) &&
25                 ObjectUtils.equals(role, other.role));
26     }
27    
28     public String getId() {
29         return id;
30     }
31     public void setId(String id) {
32         this.id = id;
33     }
34     public String getName() {
35         return name;
36     }
37     public void setName(String name) {
38         this.name = name;
39     }
40     public String getRole() {
41         return role;
42     }
43     public void setRole(String role) {
44         this.role = role;
45     }
46 }其中ObjectUtils類的代碼如下:
 1 public class ObjectUtils {
 2    
 3     /**
 4      * Compare whether the left and right is equals
 5      * It has already considered the null case
 6      *
 7      * @param left
 8      * @param right
 9      * @return
10      */
11     public static boolean equals(Object left, Object right) {
12         if(left == null && right == null) {
13             return true;
14         }
15         if(left == null && right != null) {
16             return false;
17         }
18         return left.equals(right);
19     }
20 }在《Effective Java》這本書中,貌似equals實現方法前面沒有null、this的判斷,因為instanceof可以解決null的問題,而super.equals()方法可以解決this問題,但是我還是喜歡把它們都分出來,這樣寫的更加明了一些。另外,事實上,這裡的實現並沒有遵循對稱性的原則,因為如果A是B的子類,而這個equals方法在A類中,那麼AInstance.equals(BInstance)==false,若B也實現了類似的equals方法,則BInstance.equals(AInstance)==true(當A沒有新的比較字段時,或許這個時候A根本就不需要實現equals方法,如本文開頭列出的第三條),這是因為AInstance instanceof BInstance == true,反之則為false。不過由於這種情況並不常見,所以就不去care了。:)

    事實上,這裡我之所以要記錄這些代碼,主要是因為有ObjectUtils類的存在。記得以前在學C#的時候,它的Object類提供了一個靜態的Equals方法,我一直對這個方法的存在感到很疑問,直到這次自己寫這個equals方法才弄明白,因為雖然在equals方法實現中,最後還要判斷類字段是否equals,然後這些字段都有可能是null的,如果沒有提供這個靜態的equals方法,我們就需要自己來判斷每個字段是否為null,然後才可以調用它的equals方法,這樣就比較麻煩了,而Object.Equals方法正是對這種行為的封裝,我們只要使用一個方法就可以安全的實現類成員的equals。這也是我加ObjectUtils類的意義所在。希望以後能有機會向這個ObjectUtils類填充更多的實用方法。:)

PS:如一樓所說在commons中的EqualsBuilder已經實現了相同的功能,而且代碼更加完善,有興趣的可以看看那裡的代碼,我這裡只是對這次新的的記錄,代碼只是對當前我考慮的場景中使用,並沒有考慮其他方面。另外,在《Effective Java》中也是建議equals和hashCode兩個方法應該是同時實現的,一樓也有說可以用HashCodeBuider來實現,這個大家也不妨可以去看看裡面的源碼,最近時間不多,以後回來再看。。。。。。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved