Comparable自然排序
public interface Comparable<T>此接口强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序,类的 compareTo 方法被称为它的自然比较方法。
我们应该如何对事物进行比较和排序?这问题听上去有点莫名其妙,但我希望你认真考虑一下。比方说,我们有一组苹果:
例1
我们要怎样对它们进行排序呢?我们希望通过重量进行排序吗?如果是的话,排序是从最轻到最重还是从最重到最轻?当我们对它们进行排序的时候,我们需要反复比较两个苹果的重量,直到正确地排好所有的苹果。苹果1比苹果2重?那它比苹果3重吗?我们需要不断比较,直到完成排序。Comparable接口可以帮助我们实现这一目标。Comparable本身不能对对象进行排序,但接口定义的方法 int compareTo(T)可以。
compareTo(T)如何工作
让我们通过使用compareTo()方法来看看哪个苹果更重,开始吧。
例2
compareTo()方法的工作原理是返回一个int值——或正,或负,或为零。它通过调用作为参数的对象来比较对象。负数表示调用的对象比参数“轻”。如果我们用大小来比较苹果,那么上面的调用会返回一个负数,例如-400,因为红苹果比青苹果小。如果两个苹果重量相等,那么调用将返回0。如果红苹果更重,那么compareTo()将返回一个正数,例如68。
compareTo()的灵活性
如果我们反复调用上面的compareTo()方法,那么我们可以通过大小来排序,这很棒,但并非故事的结束。如果我们想通过颜色来给苹果排序呢?抑或是重量?
他可以通过回答这两个问题来做到这一点:
- 他希望苹果如何进行排序?他希望我们比较什么特征?
- 在那样的环境中,“小于”,“等于”和“大于”指的是什么意思?
例1:通过重量排序苹果
在第一个例子中,我们将通过重量对苹果排序。只需要一行代码。
Collections.sort(apples);
上面的代码行可以为我们做到所有的排序工作,只要我们事先定义好如何对苹果进行排序。
让我们开始写苹果类吧。
public class Apple implements Comparable {
private String variety;
private Color color;
private int weight;
@Override
public int compareTo(Apple other) {
if (this.weight < other.weight) {
return -1;
}
if (this.weight == other.weight) {
return 0;
}
return 1;
}
}
例2:通过多个特征排序苹果
@Override
public int compareTo(Apple other) {
int result = this.variety.compareTo(other.variety);
if (result == 0) {
result = this.color.compareTo(other.color);
}
if (result == 0) {
result = Integer.compare(this.weight, other.weight);
}
return result;
}
Comparable,hashCode以及Equals
你可能会注意到compareTo()看起来有点像hashCode()和equals()方法。但是,它们有一个重要的区别。对于hashCode()和equals()方法,比较个体属性的顺序不影响返回的值,但是,在compareTo()中,通过你比较对象的顺序来定义对象的顺序。
结论
在结论中我只想强调Comparable接口是多么的重要。它既用于java.util.Arrays,也用于java.util.Collections实用程序类,来排序元素和搜索排序集合中的元素。使用TreeSet和Tree Map,就更简单了——想要它们会自动排序必须实现Comparable接口的元素。
Comparator 定制排序
Comparator 在 java.util 包下,也是一个接口,JDK 1.8 以前只有两个方法:
public interface Comparator<T> {
public int compare(T lhs, T rhs);
public boolean equals(Object object);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
JDK 1.8 以后又新增了很多方法:
Comparator 是在外部制定排序规则,然后作为排序策略参数传递给某些类,比如 Collections.sort(), Arrays.sort(), 或者一些内部有序的集合(比如 SortedSet,SortedMap 等)。
举个例子:
// 1.创建一个实现 Comparator 接口的对象
Comparator comparator = new Comparator() {
@Override
public int compare(Object object1, Object object2) {
if (object1 instanceof NewBookBean && object2 instanceof NewBookBean){
NewBookBean newBookBean = (NewBookBean) object1;
NewBookBean newBookBean1 = (NewBookBean) object2;
//具体比较方法参照 自然排序的 compareTo 方法,这里只举个栗子
return newBookBean.getCount() - newBookBean1.getCount();
}
return 0;
}
};
//2.将此对象作为形参传递给 TreeSet 的构造器中
TreeSet treeSet = new TreeSet(comparator);
//3.向 TreeSet 中添加 步骤 1 中 compare 方法中设计的类的对象
treeSet.add( new NewBookBean("A",34));
treeSet.add( new NewBookBean("S",1));
treeSet.add( new NewBookBean("V",46));
treeSet.add( new NewBookBean("Q",26));
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
其实可以看到,Comparator 的使用是一种策略模式,不熟悉策略模式的同学可以点这里查看: 策略模式:网络小说的固定套路 了解。
排序类中持有一个 Comparator 接口的引用:
Comparator<? super K> comparator;
- 1
- 2
而我们可以传入各种自定义排序规则的 Comparator 实现类,对同样的类制定不同的排序策略。
总结
Java 中的两种排序方式:
- Comparable 自然排序。(实体类实现)
- Comparator 是定制排序。(无法修改实体类时,直接在调用方创建)
同时存在时采用 Comparator(定制排序)的规则进行比较。
对于一些普通的数据类型(比如 String, Integer, Double…),它们默认实现了Comparable 接口,实现了 compareTo 方法,我们可以直接使用。
而对于一些自定义类,它们可能在不同情况下需要实现不同的比较策略,我们可以新创建 Comparator 接口,然后使用特定的 Comparator 实现进行比较。
这就是 Comparable 和 Comparator 的区别。
http://www.codeceo.com/article/java-comparable-5-minutes.html。https://blog.csdn.net/u011240877/article/details/53399019