2012-07-30 91 views
3

必须首次定义相关对象之间的关系,我发现自己花费整个周末在网上搜索关于equals()compareTo()的干净覆盖实现的信息。找到很少有用的信息后,我决定寻找解决方案。我相信以下方法是compareTo()方法的解决方案的一种体现。我有一个想法,类似的技术也可以用于equals()方法。干净的可重写的compareTo()方法?

我的希望是,比我聪明的人可能有时间来验证这些发现并提供有关可能遇到的任何缺陷的反馈。

// The name chosen for the following class shell ("Base") is intended to 
// portray that this compareTo() method should be implemented on a base class 
// as opposed to a subclass. 
public class Base 
implements Comparable<Base> 
{ 
    /** 
    * Compares this Base to the specified Object for semantic ordering. 
    * 
    * @param other The Object to be compared. 
    * 
    * @return An int value representing the semantic relationship between the 
    *   compared objects. The value 0 is returned when the two objects 
    *   are determined to be equal (as defined by the equals method). 
    *   A positive value may be returned if the "other" object is a 
    *   Base and the "exact types" comparison determines this Base to 
    *   have a higher semantic ordering than the "other" object, if the 
    *   "other" object is not a Base, or if the "other" object is a 
    *   subclass of Base who's compareTo method determines itself to 
    *   have a lower semantic ordering than this Base. A negative value 
    *   may be returned if the "other" object is a Base and the 
    *   "exact types" comparison determines this Base to have a lower 
    *   semantic ordering than the "other" object or if the "other" 
    *   object is a subclass of Base who's compareTo method determines 
    *   itself to have a higher semantic ordering than this Base. 
    */ 
    public int compareTo(Base other) 
    { 
     int relationship = 0; 

     if (other == null) 
      throw new NullPointerException("other: Cannot be null."); 

     if (!this.equals(other)) 
     { 
      if (this.getClass() == Base.class) 
      { 
       if (this.getClass == other.getClass()) 
        relationship = // Perform comparison of exact types; 
       else 
        relationship = -1 * other.compareTo(this); 
      } 
      else 
       relationship = 1; 
     } 

     return relationship; 
    } 
+0

好吧,我想我已经找到了一种方法来解决泰德提出的问题,同时也允许一些额外的自由。一旦我完成了更多的事情,我会发布一个新的解决方案。 – blf 2012-08-01 01:17:03

回答

3

这是行不通的。考虑两个类,AB,直接延伸Base,其实例永远不会相等。然后是两个实例Base a = new A();Base b = new B()。由于this.getClass() == Base.class对于ab都将是false,因此a.compareTo(b) == 1b.compareTo(a) == 1将是这种情况。这违反了Comparable的一般合同,即所有xysgn(x.compareTo(y)) == -sgn(y.compareTo(x))都具有可比性。

对于比较对象所涉及的一些微妙之处,特别是测试子类之间的相等性,我推荐this excellent article

+0

特德,谢谢你的出色反应。虽然答案不幸,但它肯定给我一个继续工作的地方。 – blf 2012-07-30 08:03:36

0

正如主题发起人所述,由于缺乏可用信息,因此缺乏可用的信息,详细说明了建立干净地覆盖的compareTo()方法背后的过程。我希望你会发现以下是这样一个实现。 Ted Hopp补充指出了我最初忽略的一些关键因素。

你会发现RelationalObject的实现并没有定义除了那些不是来自同一个分层结构的元素之外的任何元素之间的初始关系,它认为它是无法比拟的(当然,它是可覆盖的)。由于这个类可能实现的任何关系都不能考虑派生类的状态元素,我已经确定最好将这个任务完全留给用户。

此类所打算做的事情是更容易更改新子类型(包括当前未实现的子类型)的关系行为。

因为我在主题发起人中表达了对文档的渴望,所以我对每种方法进行了大量评论,希望它能提供一些指导。

我希望有足够的时间的人可能愿意提供这些结果的验证。虽然我已尽力考虑所有可能的情况,但获得反馈总是很好的。 (正面或负面)

public abstract class RelationalObject 
implements Comparable<RelationalObject> 
{ 
    /* 
    * Compares two RelationalObjects for semantic ordering. 
    * 
    * @param other The RelationalObject to be compared. 
    * 
    * @return An int value representing the semantic relationship between the 
    *   two RelationalObjects. A value of 0 is returned if the two 
    *   objects are determined to be equal. A negative value is 
    *   returned if "this" object is determined to have a 
    *   lower semantic ordering than the "other" object. A positive 
    *   value is returned if "this" object is determined to have a 
    *   highter semantic ordering than the "other" object. 
    */ 
    public final int compareTo(RelationalObject other) 
    throws ClassCastException, NullPointerException 
    { 
     if (other == null) 
      throw new NullPointerException("other: Cannot be null."); 

     int relation = 0; 

     if (!this.equals(other)) 
     { 
      if (this.getClass().isAssignableFrom(other.getClass())) 
      { 
       if (this.getClass() == other.getClass()) 
        relation = this.compareToExactType(other); 
       else 
        relation = -1 * other.compareTo(this); 
      } 
      else 
      { 
       if (other.getClass().isInstance(this)) 
        relation = this.compareToSuperType(other); 
       else 
        relation = other.compareToForeignType(this); 
      } 
     } 

     return relation; 
    } 

    /* 
    * Compares two RelationalObjects with the exact same class type for 
    * semantic ordering. The comparison may be based upon any of the class 
    * state elements so long as the compareTo() method contract is not 
    * broken. 
    * 
    * @param exact The RelationalObject with exactly matching type to be 
    *    compared. 
    * 
    * @return An int value representing the semantic relationship between the 
    *   two RelationalObjects. 
    */ 
    protected abstract int compareToExactType(RelationalObject exact); 

    /* 
    * Compares two RelationalObjects not within the same hierarchical branch 
    * for semantic ordering. The comparison may be based upon only those 
    * state elements common to both objects (i.e. A comparison must be made 
    * between each element and the pair's common ancestor). Should the two 
    * results be equal, a ClassCastException must be thrown as the objects do 
    * not contain enough distinct information to be further compared. 
    * 
    * @param foreign The RelationalObject from a foreign hierarchical branch 
    *    to be compared. 
    * 
    * @return An int value representing the semantic relationship between the 
    *   two RelationalObjects. 
    */ 
    protected abstract int compareToForeignType(RelationalObject foreign); 

    /* 
    * Compares two RelationalObjects within the same class hierarchical 
    * branch for semantic ordering. The comparison may be based upon any of 
    * the class state elements so long as the compareTo() method contract is 
    * not broken. 
    * 
    * @param upper The RelationalObject within the same heirarchical branch 
    *    and with lesser definition to be compared. 
    * 
    * @return An int value representing the semantic relationship between the 
    *   two RelationalObjects. 
    */ 
    protected abstract int compareToSuperType(RelationalObject upper); 
}