当参数必须为超类类型时,compareTo() 的最佳实践

发布于 2024-11-29 15:57:29 字数 284 浏览 0 评论 0原文

我正在寻找在类实现 Comparable 的情况下定义compareTo()方法的最佳实践。因此,方法的签名必须是。

public int compareTo(BaseClass arg)

首先要做的显而易见的事情是检查 arg 是否是此类的实例,如果是,则转换为该类,并比较成员。但是,如果参数不是这个类的,而是某个也实现 BaseClass 的其他类,我应该返回什么以使其具有自反性?

我知道,最好的做法是只为它所在的类定义compareTo(),但水已经过了大坝。

I'm looking for best practice for the definition of the compareTo() method in the case where the class implements Comparable. Thus, the signature of the method has to be

public int compareTo(BaseClass arg)

The obvious thing to do first is check if the arg is an instanceof this class, and if so, cast to the class, and compare the members. But if the argument is not of this class, but rather some other class that also implements BaseClass, what do I return so that its reflexive?

I know, the very best practices would be to define compareTo() only for the class it is, but that water is over the dam.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

夜血缘 2024-12-06 15:57:29

引自《Effective Java》第 12 条:

让我们回顾一下compareTo 合约的条款。第一个
规定说如果你颠倒比较的方向
在两个对象引用之间,预期的事情会发生:如果
第一个对象小于第二个,那么第二个对象必须大于
比第一个;如果第一个对象等于第二个对象,则
第二个必须等于第一个;如果第一个物体更大
比第二个小,那么第二个一定小于第一个。这
第二条规定,如果一个物体大于一秒,
并且第二个大于第三个,那么第一个必须是
大于第三个。最终条款规定,所有反对
与任何比较时,比较为相等必须产生相同的结果
其他对象。

这三个规定的一个后果是平等测试
由 acompareTo 方法施加的限制必须遵守相同的限制
遵循平等契约:自反性、对称性和传递性。
因此,同样的警告也适用:没有办法延长
具有新值组件的实例化类,同时保留
比较合同,除非你愿意放弃的好处
面向对象的抽象(第 8 项)。
同样的解决方法适用,
也。如果您想向实现的类添加值组件
可以比较,不要扩展;编写一个不相关的类,其中包含
第一类的实例。然后提供一个“查看”方法
返回此实例。这使您可以自由地实现任何compareTo
您喜欢在第二个类中使用您喜欢的方法,同时允许其客户端
将第二个类的实例视为第一个类的实例
当需要时。

您应该执行@BalusC 在他的评论中建议的操作——对所有子类使用基类的compareTo() 方法,或者通过创建一个包含第一个类的实例的不相关的类来执行上面建议的解决方法。

Quote from Effective Java, Item 12:

Let’s go over the provisions of the compareTo contract. The first
provision says that if you reverse the direction of a comparison
between two object refer- ences, the expected thing happens: if the
first object is less than the second, then the second must be greater
than the first; if the first object is equal to the second, then the
second must be equal to the first; and if the first object is greater
than the second, then the second must be less than the first. The
second provision says that if one object is greater than a second,
and the second is greater than a third, then the first must be
greater than the third. The final provision says that all objects that
compare as equal must yield the same results when compared to any
other object.

One consequence of these three provisions is that the equality test
imposed by acompareTo method must obey the same restrictions imposed
by the equals con- tract: reflexivity, symmetry, and transitivity.
Therefore the same caveat applies: there is no way to extend an
instantiable class with a new value component while preserving the
compareTo contract, unless you are willing to forgo the benefits of
object-oriented abstraction (Item 8).
The same workaround applies,
too. If you want to add a value component to a class that implements
Comparable, don’t extend it; write an unrelated class containing an
instance of the first class. Then provide a “view” method that
returns this instance. This frees you to implement whatever compareTo
method you like on the second class, while allowing its cli- ent to
view an instance of the second class as an instance of the first class
when needed.

You should do what @BalusC recommended in his comment -- use the compareTo() method of the base class for all children classes, OR do the workaround suggested above by creating an unrelated class containing an instance of the first class.

淑女气质 2024-12-06 15:57:29

你的错误在于你的问题。
您不必实现public intcompareTo(BaseClass arg)。您必须实现“public int CompareTo(YourClass arg)”。

在这种情况下,您不必使用 instanceof 并执行强制转换。这就是引入泛型的原因:避免强制转换。

但是,如果您仍然想使用基类作为参数,请至少执行以下操作:

public class Test {

}

class SubTest <T extends Test> implements Comparable<T> {
    @Override
    public int compareTo(T o) {
        // add your code with instanceof here
        return 0;
    }
}

至少此方法要求参数是基类的子类。

Your mistake is in your question.
You do not have to implement public int compareTo(BaseClass arg). You have to implement 'public int compareTo(YourClass arg)'.

In this case you do not have to use instanceof and perform cast. This is why generics were introduced: to avoid casting.

But if you still want to use base class as an argument do at least the following:

public class Test {

}

class SubTest <T extends Test> implements Comparable<T> {
    @Override
    public int compareTo(T o) {
        // add your code with instanceof here
        return 0;
    }
}

At least this approach requires that the argument is subclass of your base class.

似最初 2024-12-06 15:57:29

在这种情况下,自反意味着 obj.compareTo(obj) == 0。这里的反身是什么意思?

就compareTo(T o) 的指定约定而言,如果所涉及的类无法进行有意义的比较,则所需的语义是抛出 ClassCastException。

例如,鉴于

class Fruit {/* ..*/ }

class Apple extends Fruit {/* .. */ }

@Ignore("bad OO")
class GrannySmithApple extends Apple {/* .. */ }

class Orange extends Fruit {/* ... */ }

有人可能会争辩说

   Fruit a = new Apple();
   Fruit b = new GrannyApple();
   Fruit c = new Orange();

   // compare apples with apple?
   // makes sense to expect an int value
   r = a.compareTo(b)

   // compare apples with oranges?
   // makes sense to expect an exception
   boolean excepted = false;
   try {
       c.compareTo(a);
   } catch (ClassCastException e) { 
      excepted = true;
   } finally {
      assert excepted : "How can we compare apples with oranges?"
   }

In this context reflexive means obj.compareTo(obj) == 0. What do you mean by reflexive here?

As far as the specified contract for compareTo(T o), the required semantics are for you to throw a ClassCastException if the classes involved can not meaningfully be compared.

e.g. Given

class Fruit {/* ..*/ }

class Apple extends Fruit {/* .. */ }

@Ignore("bad OO")
class GrannySmithApple extends Apple {/* .. */ }

class Orange extends Fruit {/* ... */ }

one could argue that

   Fruit a = new Apple();
   Fruit b = new GrannyApple();
   Fruit c = new Orange();

   // compare apples with apple?
   // makes sense to expect an int value
   r = a.compareTo(b)

   // compare apples with oranges?
   // makes sense to expect an exception
   boolean excepted = false;
   try {
       c.compareTo(a);
   } catch (ClassCastException e) { 
      excepted = true;
   } finally {
      assert excepted : "How can we compare apples with oranges?"
   }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文