Effective Java_13 考虑实现Comparable接口

实现该接口,就表明该类的实例具有内在的排序关系。为实现Comparable接口的对象数组a 进行排序可以使用:

Arrays.sort(a)

事实上,Java平台类库中的所有值类都实现了Comparable接口。如果你正在编写一个值类,它具有非常明显的内在排序关系,比如按字母排序、按数值排序或者按年代排序,那么你就应该坚决考虑实现这个接口。

Comparable接口只有一个方法,就是compareTo方法。compareTo方法的通用约定与equals方法的相似:
将这个对象与指定的对象进行比较。当该对象小于、等于或大于指定对象的时候,分别返回一个负整数、零或者正整数。如果由于指定对象的类型而无法与该对象进行比较,则跑出ClassCastException异常

compareTo的等同性测试,在通常情况下应该返回与equals方法同样的结果。但是如果结果不一致,它仍然能够正常工作。但是,如果一个有序集合包含了该类的元素,这个集合就可能无法遵守相应集合接口的通用约定。这是因为,对于这些接口的通用约定是按照equals方法来定义的,但是有序集合使用了由compareTo方法而不是equals方法所施加的等同性测试。尽管出现这种情况不会造成灾难性的后果,但是应该有所了解。
比如,BigDecimal类,它的compareTo方法与equals方法不一致。如果你创建了一个HashSet实例,并且添加new BigDecimal(“1.0”)和new BigDecimal(“1.00”),这个集合就将包含两个元素,因为这两个元素的equals方法比较是不相同的。然而,如果你使用TreeSet而不是HashSet来执行同样的过程,集合中将只包含一个元素,因为这两个元素通过compareTo方法进行比较是是相等的。
compareTo方法与equals方法不一致
如果一个域并没有实现Comparable接口,或者你需使用一个非标准的排序关系,就可以使用一个现实的Comparator来代替。编写自己的Comparator,或者使用已有的Comparator。

public final class CaseInsensitiveString implements Comparable<CaseInsensitiveString> {
    public int compareTo(CaseInsensitiveString cis) {
        return String.CASE_INSENSITIVE_ORDER.compare(s, cis.s);
    }
    ... // Remainder omitted
}

如果一个类有多个关键域,那么,你必须从最关键的域开始,逐步进行到所有的重要域。如果某个与的比较产生了非零的结果,则整个比较操作结束,并返回该结果。如果最关键的域是相等的,则进一步比较次关键的域,以此类推。

public class PhoneNum implements Comparable<PhoneNum>{
    private short areaCode;
    private short prefix;
    private short lineNumber;

    @Override
    public int compareTo(PhoneNum pn) {
        if (areaCode < pn.areaCode) {
            return -1;
        }
        if (areaCode > pn.areaCode) {
            return 1;
        }
        if ( prefix< pn.prefix) {
            return -1;
        }
        if (prefix > pn.prefix) {
            return 1;
        }
        if (lineNumber < pn.lineNumber) {
            return -1;
        }
        if (lineNumber < pn.lineNumber) {
            return 1;
        }
        return 0;
    }
    // getter and setter
}

虽然这个方法可行,但它还可以进行改进。compareTo方法的约定并没有指定返回值得大小,而只是指定了返回值得符号。你可以利用这一点来简化代码

@Override
    public int compareTo(PhoneNum pn) {
        int areaCodeDiff = areaCode - pn.areaCode;
        if (areaCodeDiff != 0) {
            return areaCodeDiff;
        }

        int prefixDiff = prefix - pn.prefix;
        if (prefixDiff != 0) {
            return prefixDiff;
        }

        int lineNumberDiff = lineNumber - pn.lineNumber;
        if (lineNumberDiff != 0) {
            return lineNumberDiff;
        }

        return 0;
    }

但是这样有个风险,当你不确定这个域的值时,请谨慎使用,因为有可能最小和最大的域值只差大于INTEGER.MAX_VALUE(2^31 - 1)而导致出现错误。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值