在学习 String类源码的时候,发现了 Comparable接口,觉得有必要先学习一下这个接口的用法。
Comparable接口对实现它的每个类的对象强加一个总排序,这种排序被称为类的自然排序,类的compareTo方法被称为自然比较方法。
实现此接口的对象的列表(和数组)可以通过Collections.sort()
,以及Arrays.sort()
自动排序。实现此接口的对象可以用作SortedMap有序映射中的键,也可以用作SortedSet有序集中的元素,而无需指定比较器。
① null不是任何类的实例,并且e.compareTo(null)应抛出NullPointerException;
② 当且仅当e1.compareTo(e2)== 0
具有与C类的每个e1和e2的e1.equals(e2)
相同的布尔值时,C类的自然排序被认为与equals一致。这里注意,并不是规定自然排序与equals要一致,而是强烈建议(尽管不要求)自然排序与equals一致。几乎所有实现Comparable接口的Java核心类都具有与equals一致的自然排序。一个例外是java.math.BigDecimal
,其自然顺序等同于具有相同值和不同精度的BigDecimal对象(例如4.0和4.00)
打开 Comparable接口的源码,发现只有一个方法:
public interface Comparable<T> {
/**
* @param o 用于比较的对象
* @return 负整数,零或正整数,对应此对象小于,等于或大于传入的比较对象
* @throws NullPointerException 传入的 o为 null
* @throws ClassCastException 传入的 o的对象类型阻止与此对象进行比较
*/
public int compareTo(T o);
}
要实现 Comparable接口,则要实现该方法,而实现方法时应注意:
① 实现者必须确保所有x和y的sgn(x.compareTo(y)) == -sgn(y.compareTo(x))
。这意味着如果y.compareTo(x)
抛出异常,x.compareTo(y)
必须抛出异常。(符号sgn
表达式表示数学signum
函数,定义为返回 -1,0,1 其中一个,根据表达式的值为负,零或正)
② 实现者还必须确保关系是可传递的。x.compareTo(y) == 0 && y.compareTo(z) == 0
可以推导:x.compareTo(z) == 0
③ 实现者必须确保x.compareTo(y) == 0
意味着sgn(x.compareTo(z)) == sgn(y.compareTo(z))
,对于所有z都成立
④ 最后,强烈建议,但不严格要求(x.compareTo(y) == 0) == (x.equals(y))
关于最后这一点强烈建议,在 jdk1.8中给出的原因是:
!a.equals(b) && (a.compareTo(b) == 0)
对于不使用显式比较器的有序集,第二个 add操作返回false(并且有序集的大小不会增加),因为 a和 b在有序集的透视图中是等效的对于已经实现了 Comparable接口的类,正如我们上面提到的:
Collections.sort()
,以及Arrays.sort()
自动排序例如,对于 Integer类,其源码中已经实现了 Comparable接口:
public final class Integer extends Number implements Comparable<Integer> {}
因此:
public static void main(String[] args) {
Integer[] a = new Integer[]{1, 15, 6, 18, 50, 3};
Arrays.sort(a);
for (Integer k : a
) {
System.out.print(k + " ");
}
}
例如对于下面的类:
public class User {
private String name;
private String phoneNumber;
private Integer old;
User(){}
User(Integer old) {
this.old = old;
}
// get、set方法
}
我们要实现跟上面的 Integer一样,用Arrays.sort()
排序,该如何做呢?
我们先直接进行测试:
public static void main(String[] args) {
User[] users = new User[5];
users[0] = new User(50);
users[1] = new User(5);
users[2] = new User(4);
users[3] = new User(30);
users[4] = new User(1);
Arrays.sort(users);
for (User user : users
) {
System.out.println(user.toString());
}
}
public class User implements Comparable<User> {
@Override
public int compareTo(User o) {
if (this.old > o.old) {
return 1;
} else if (this.old < o.old) {
return -1;
} else {
return 0;
}
}
// 省略其他函数
}
再次执行结果:
而且,此使执行:new User(5).compareTo(null);
满足 Comparable接口的要求