Comparable简介
接口定义:
package java.lang;
import java.util.*;
public interface Comparable<T>
{
public int compareTo(T o);
}
文档:
此接口强行对实现它的每个类的对象进行整体排序。这种排序称为类的自然(native)排序。类的compareTo方法被称为它的自然(native)比较方法
列表(或数组)中的元素如果实现此接口,那么该列表(或数组)可以通过Collection.sort()和Arrays.sort()进行自动的排序。实现此接口的对象可以用作SortedMap的key或者SortedSet的元素,而不用额外指定比较器(comparator)
对于类C的实例e1,e2来说仅当e1.compareTo(e2) == 0
和 e1.equals(e2)
具有相同的boolean值时,类C的自然排序才叫做与equals一致。注意null 不是任何类的实例,e.compareTo(null)
应当抛出NullPointerException即使e.equals(null)
返回false
建议(虽然不是必需的)最好使自然排序与 equals 一致。这是因为在使用自然排序与 equals 不一致的元素(或键)时,没有显式比较器的SortedSet(和SortedMap)行为表现“怪异”。尤其是,这样的有序集合(或有序映射表)违背了根据 equals 方法定义的集合(或映射表)的常规协定。
例如,如果将两个键 a 和 b 添加到没有使用显式比较器的有序集合中,使 (!a.equals(b) && a.compareTo(b) == 0),那么第二个 add 操作将返回 false(有序集合的大小没有增加),因为从有序集合的角度来看,a 和 b 是相等的。
实际上,所有实现 Comparable 的 Java 核心类都具有与 equals 一致的自然排序。java.math.BigDecimal 是个例外,它的自然排序将值相等但精确度不同的 BigDecimal 对象(比如 4.0 和 4.00)视为相等
从数学上讲,定义给定类 C 上自然排序的关系式 如下:
{(x, y)|x.compareTo(y) <= 0}。
整体排序的 商 是:
{(x, y)|x.compareTo(y) == 0}。
它直接遵循 compareTo 的协定,商是 C 的 等价关系,自然排序是 C 的 整体排序。当说到类的自然排序 与 equals 一致 时,是指自然排序的商是由类的 equals(Object) 方法定义的等价关系。
{(x, y)|x.equals(y)}。
public int compareTo(T o)方法介绍
文档:
比较此对象与指定对象的顺序。如果该对象小于、等于、大于指定的对象,则分别返回负整数、零、或正整数。
实现类对于所有的实例x, y必须确保sgn(x.compareTo(y)) == -sng(y.compareTo(x))
。(这意味着如果y.compareTo(x)
抛出异常,x.compareTo(y)
也要抛出异常)。
实现类还必须确保关系是可传递的:(x.compareTo(y)>0 && y.compareTo(z)>0)
意味着 x.compareTo(z)>0
最后,实现者必须确保 x.compareTo(y)==0 意味着对于所有的 z,都存在 sgn(x.compareTo(z)) == sgn(y.compareTo(z))。
强烈推荐 (x.compareTo(y)==0) == (x.equals(y))
这种做法,但并不是 严格要求这样做。一般来说,任何实现 Comparable 接口和违背此条件的类都应该清楚地指出这一事实。推荐如此阐述:“注意:此类具有与 equals 不一致的自然排序。”
在前面的描述中,符号 sgn(expression) 指定 signum 数学函数,该函数根据 expression 的值是负数、零还是正数,分别返回 -1、0 或 1 中的一个值。
Compatator简介
定义
package java.util;
public interface Comparator<T>
{
int compare(T o1, T o2);
boolean equals(Object obj);
}
此类的文档与Compable的文档相似,
compare方法的介绍也与Compable.compareTo方法的介绍相似
在此不过多介绍。
equals方法
文档:
指示某个其他对象是否“等于”此 Comparator
。此方法必须遵守 Object.equals(Object)
的常规协定。此外, 仅当 指定的对象也是一个 Comparator
,并且强行实施与此 Comparator
相同的排序时,此方法才返回 true。因此,comp1.equals(comp2)
意味着对于每个对象引用 o1
和o2
而言,都存在 sgn(comp1.compare(o1, o2))==sgn(comp2.compare(o1, o2))
。
注意,不 重写 Object.equals(Object)
方法总是 安全的。然而,在某些情况下,重写此方法可以允许程序确定两个不同的 Comparator
是否强行实施了相同的排序,从而提高性能。
Comparable和Comparator区别比较
Comparable是排序接口,若一个类实现了Comparable接口,就意味着“该类支持排序”。而Comparator是比较器,我们若需要控制某个类的次序,可以建立一个“该类的比较器”来进行排序。
Comparable相当于“内部比较器”,而Comparator相当于“外部比较器”。
两种方法各有优劣:
用Comparable 简单, 只要实现Comparable 接口的对象直接就成为一个可以比较的对象,但是需要修改源代码。
用Comparator 的好处是不需要修改源代码, 而是另外实现一个比较器, 当某个自定义的对象需要作比较的时候,把比较器和对象一起传递过去就可以比大小了, 并且在Comparator 里面用户可以自己实现复杂的可以通用的逻辑,使其可以匹配一些比较简单的对象,那样就可以节省很多重复劳动了。
参考
- jdk源码及api
- Java中Comparable和Comparator区别小结