Comparable接口compareTo方法的反对称性

来源:互联网 发布:网络预警包括什么预警 编辑:程序博客网 时间:2024/04/28 15:13
以下是阅读《Core Java 卷一》的感悟,具体内容见该书关于接口的章节。

Java要求Comparable接口的compareTo方法具有反对称性。即a.compareTo(b)和b.compareTo(a)的符号相反。同时,如果a.compareTo(b)抛出异常,b.compareTo(a)也必须抛出异常。
引入继承后,这一点尤为值得注意。

假设Employee是父类,其实现了Comparable<Employee>接口,实现了其中的compareTo方法,
public int compareTo(Employee other){     ...},
而Manager是Employee类的子类,现在Manager类想要重写继承的compareTo方法。则Manager类不可以直接进行强制类型转换:
public int compareTo(Employee other){   Manager otherManager = (Manager) other; // NO   . . .}
这是因为,假设a是Manager对象,b是Employee对象,则b.compareTo(a)没有任何问题,调用Employee的compareTo,比较的是b和a的Employee部分,而此时a.compareTo(b),将会调用Manager中的compareTo,由于无法将一个Employee对象强制转为Manager对象,此时该compareTo方法会抛出异常。这就造成了b.compareTo(a)不抛异常,而a.compareTo(b)抛出了异常,这就违背了compareTo方法具有反对称性的要求。
那么出现这种情况怎么办呢?
有人说Manager类重写compareTo方法时不去强制转换参数不就都不会抛出异常了吗?但是如果不去转换Employee参数的话,Employee参数即使引用的是一个Manager对象,也只能访问其Employee部分,即只能比较两个Manager对象的Employee成分,那这样就没有必要重写compareTo方法了。所以这种思路是行不通的。
从以上分析可以看出,如果子类选择重写父类的compareTo方法,则必须要对重写方法的参数进行类型转换,使其转为子类对象。否则,重写就没有必要。直接使用继承自父类的compareTo方法便可。而直接进行强制类型转换又会带来上述的违背反对称性的问题。所以要解决这个问题,就需要在父类和子类各自的compareTo方法中一开始就判断方法的调用对象和参数对象是否属于同一个Class,如果不属于,则抛出异常。
                                             if (getClass() != other.getClass()) throw new ClassCastException();
这样,当a是Employee对象,b是Manager对象时,无论a.compareTo(b)还是b.compareTo(a)都会抛出异常。当a和b都是Employee对象时,a.compareTo(b),b.compareTo(a)都会调用Employee 的compareTo方法,当a和b都是Manager对象时,a.compareTo(b),b.compareTo(a)都会调用Manager的comareTo方法,而且这时候的类型转换一定是成功的。
1 0
原创粉丝点击