实现该接口,就表明该类的实例具有内在的排序关系。为实现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方法进行比较是是相等的。
如果一个域并没有实现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)而导致出现错误。