我正在寻找在类实现 Comparable 的情况下定义 compareTo() 方法的最佳实践。因此,方法的签名必须是
public int compareTo(BaseClass arg)
首先要做的显而易见的事情是检查 arg 是否是此类的实例,如果是,则强制转换为该类,并比较成员。但是,如果参数不是这个类,而是其他一些也实现 BaseClass 的类,我应该返回什么以便它具有自反性?
我知道,最好的做法是只为它所在的类定义 compareTo(),但是水已经超过了大坝。
我正在寻找在类实现 Comparable 的情况下定义 compareTo() 方法的最佳实践。因此,方法的签名必须是
public int compareTo(BaseClass arg)
首先要做的显而易见的事情是检查 arg 是否是此类的实例,如果是,则强制转换为该类,并比较成员。但是,如果参数不是这个类,而是其他一些也实现 BaseClass 的类,我应该返回什么以便它具有自反性?
我知道,最好的做法是只为它所在的类定义 compareTo(),但是水已经超过了大坝。
引自 Effective Java,第 12 条:
让我们回顾一下 compareTo 合约的规定。第一条规定如果你颠倒两个对象引用之间的比较方向,预期的事情就会发生:如果第一个对象小于第二个,那么第二个必须大于第一个;如果第一个对象等于第二个,那么第二个必须等于第一个;如果第一个对象大于第二个,那么第二个必须小于第一个。第二条规定,如果一个对象大于第二个,而第二个大于第三个,则第一个必须大于第三个。最后一条规定说,所有比较相等的对象在与任何其他对象比较时必须产生相同的结果。
这三个规定的一个结果是,acompareTo 方法施加的相等性测试必须遵守 equals 契约施加的相同限制:自反性、对称性和传递性。因此,同样的警告也适用: 没有办法在保留 compareTo 契约的同时用新的值组件扩展可实例化类,除非您愿意放弃面向对象抽象的好处(第 8 条)。同样的解决方法也适用。如果要为实现 Comparable 的类添加值组件,请不要扩展它;编写一个不相关的类,其中包含第一个类的实例。然后提供一个返回此实例的“视图”方法。这使您可以自由地在第二个类上实现您喜欢的任何 compareTo 方法,同时允许其客户端在需要时将第二个类的实例视为第一个类的实例。
您应该执行@BalusC 在他的评论中建议的操作——对所有子类使用基类的 compareTo() 方法,或者通过创建一个包含第一个类的实例的不相关类来执行上面建议的解决方法。
你的错误在于你的问题。您不必实施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;
}
}
至少这种方法要求参数是基类的子类。
在这种情况下,反身意味着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?"
}