我正在寻找在类实现Comparable的情况下定义compareTo()方法的最佳实践。因此,该方法的签名必须是
public int compareTo(BaseClass arg)
首先要做的显而易见的事情是检查arg是否是此类的实例,如果是,则转换为类,并比较成员。但是如果参数不是这个类,而是一些其他类也实现了BaseClass,那么我该返回什么才能反复出现呢?
我知道,最好的做法是只为它所在的类定义compareTo(),但是水已经超过了大坝。
答案 0 :(得分:3)
引自Effective Java,第12项:
让我们回顾一下compareTo合同的规定。首先 规定如果你改变比较的方向 在两个对象参考之间,预期的事情发生:如果 第一个对象小于第二个,然后第二个必须更大 比第一个;如果第一个对象等于第二个,那么 第二个必须等于第一个;如果第一个对象更大 比第二个,第二个必须小于第一个。该 第二条规定,如果一个物体大于一秒, 第二个是大于三分之一,那么第一个必须是 大于第三个。最后的条款说所有对象都是 比较等于必须产生与任何相比相同的结果 其他对象。
这三项规定的一个后果是平等测试 由acompare强加的方法必须遵守相同的限制 通过平等契约:反身性,对称性和传递性。 因此同样需要注意:没有办法扩展 具有新值组件的可实例化类,同时保留 比较合同,除非你愿意放弃它的好处 面向对象的抽象(第8项)。同样的解决方法适用, 太。如果要将值组件添加到实现的类中 可比,不要延长;写一个包含一个不相关的类 第一类的实例。然后提供一个“视图”方法 返回此实例。这将使您无需执行任何compareTo 你喜欢的第二课的方法,同时允许它的客户 将第二个类的实例视为第一个类的实例 需要时。
你应该做@BalusC在他的评论中推荐的内容 - 对所有子类使用基类的compareTo()方法,或者通过创建包含第一个类的实例的无关类来执行上面建议的解决方法。 / p>
答案 1 :(得分:2)
你的错误在你的问题中。
您不必实施public int compareTo(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;
}
}
至少这种方法要求参数是基类的子类。
答案 2 :(得分:1)
在这种情况下,反身意味着obj.compareTo(obj) == 0
。你在这里反思是什么意思?
对于compareTo(T o)的指定协定,如果涉及的类无法进行有意义的比较,则所需的语义是抛出ClassCastException。
e.g。给定
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?"
}