一个干净的可覆盖compareTo()方法?

时间:2012-07-30 07:10:26

标签: java equals compareto

第一次定义相关对象之间的关系时,我发现自己花了整整一个周末在网上搜索有关equals()compareTo()的干净可覆盖实现的信息。在找到非常有用的信息后,我决定自己寻找解决方案。我相信以下是compareTo()方法的解决方案的表现形式。我有一个想法,类似的技术也可能适用于equals()方法。

我希望比我更聪明的人可以有时间验证这些发现,并就可能遇到的任何陷阱提供反馈。

// 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;
    }

2 个答案:

答案 0 :(得分:3)

这不起作用。考虑直接扩展A并且其实例永远不相等的两个类BBase。然后是两个实例Base a = new A();Base b = new B()。由于this.getClass() == Base.classfalse a b a.compareTo(b) == 1b.compareTo(a) == 1Comparable都是sgn(x.compareTo(y)) == -sgn(y.compareTo(x))。这违反了x的一般合同,y对所有{{1}}和{{1}}具有可比性。

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

答案 1 :(得分: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);
}