在Java中对于基本数据类型,诸如Integer、double等,java可以对它们进行比较,我们开发人员不需要做任何其他的工作,但对于复杂数据类型,比如类的比较,需要开发人员定义比较的逻辑,这种比较逻辑,Java中提供了两种实现,一种是内部比较器Comparable,另一种是外部比较器Comparator,这两个比较器都是Java接口。
2. 源码介绍(Java8)内部比较器Comparable源代码在java.lang下,里面只有一个方法public int compareTo(T o);支持泛型,具体源码如下:
package java.lang; import java.util.*; public interface Comparable{ public int compareTo(T o); }
外部比较器Comparator也是一个支持泛型的接口,在java.util包下,里面有如下的成员,比较器逻辑,在它的int compare(T o1, T o2);方法中实现。
源代码如下:
package java.util; import java.io.Serializable; import java.util.function.Function; import java.util.function.ToIntFunction; import java.util.function.ToLongFunction; import java.util.function.ToDoubleFunction; import java.util.Comparators; @FunctionalInterface public interface Comparator3. 使用{ int compare(T o1, T o2); boolean equals(Object obj); default Comparator reversed() { return Collections.reverseOrder(this); } default Comparator thenComparing(Comparator super T> other) { Objects.requireNonNull(other); return (Comparator & Serializable) (c1, c2) -> { int res = compare(c1, c2); return (res != 0) ? res : other.compare(c1, c2); }; } default Comparator thenComparing( Function super T, ? extends U> keyExtractor, Comparator super U> keyComparator) { return thenComparing(comparing(keyExtractor, keyComparator)); } default > Comparator thenComparing( Function super T, ? extends U> keyExtractor) { return thenComparing(comparing(keyExtractor)); } default Comparator thenComparingInt(ToIntFunction super T> keyExtractor) { return thenComparing(comparingInt(keyExtractor)); } default Comparator thenComparingLong(ToLongFunction super T> keyExtractor) { return thenComparing(comparingLong(keyExtractor)); } default Comparator thenComparingDouble(ToDoubleFunction super T> keyExtractor) { return thenComparing(comparingDouble(keyExtractor)); } public static > Comparator reverseOrder() { return Collections.reverseOrder(); } @SuppressWarnings("unchecked") public static > Comparator naturalOrder() { return (Comparator ) Comparators.NaturalOrderComparator.INSTANCE; } public static Comparator nullsFirst(Comparator super T> comparator) { return new Comparators.NullComparator<>(true, comparator); } public static Comparator nullsLast(Comparator super T> comparator) { return new Comparators.NullComparator<>(false, comparator); } public static Comparator comparing( Function super T, ? extends U> keyExtractor, Comparator super U> keyComparator) { Objects.requireNonNull(keyExtractor); Objects.requireNonNull(keyComparator); return (Comparator & Serializable) (c1, c2) -> keyComparator.compare(keyExtractor.apply(c1), keyExtractor.apply(c2)); } public static > Comparator comparing( Function super T, ? extends U> keyExtractor) { Objects.requireNonNull(keyExtractor); return (Comparator & Serializable) (c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2)); } public static Comparator comparingInt(ToIntFunction super T> keyExtractor) { Objects.requireNonNull(keyExtractor); return (Comparator & Serializable) (c1, c2) -> Integer.compare(keyExtractor.applyAsInt(c1), keyExtractor.applyAsInt(c2)); } public static Comparator comparingLong(ToLongFunction super T> keyExtractor) { Objects.requireNonNull(keyExtractor); return (Comparator & Serializable) (c1, c2) -> Long.compare(keyExtractor.applyAsLong(c1), keyExtractor.applyAsLong(c2)); } public static Comparator comparingDouble(ToDoubleFunction super T> keyExtractor) { Objects.requireNonNull(keyExtractor); return (Comparator & Serializable) (c1, c2) -> Double.compare(keyExtractor.applyAsDouble(c1), keyExtractor.applyAsDouble(c2)); } }
内部比较器使用:实现了Comparable接口的类需要实现compareTo()方法,传入一个外部参数进行比对。
class Apple implements Comparable{ int id; double price; public Apple(int id, double price) { this.id = id; this.price = price; } public int compareTo(Apple o) { //return Double.compare(this.getPrice(),o.getPrice()); if (Math.abs(this.price-o.price)<0.001) return 0; else return (o.price-this.price)>0?1:-1; } @Override public String toString() { return "Apple{" + "id=" + id + ", price=" + price + '}'; } }
外部比较器使用:实现了Comparator接口的方法需要实现compare()方法,对外部传入的两个类进行比较,从而让外部方法在比较时调用。
class AESComparator implements Comparator{ public int compare(Apple o1, Apple o2) { if (Math.abs(o1.price-o2.price)<0.001) return 0; else{ return (o1.price-o2.price)>0?1:-1; } } }
内部比较器与外部比较器对比:
- 所在Java源码中位置不同,上面有提到
- 实现比较逻辑的方法不同
- Comparator接口代码更加灵活,与类的定义解耦,可以定义某个类的多个比较器,从而在排序时根据实际场景自由调用,Comparable接口实现后便不能改动,需要将比较的逻辑嵌入到类定义的内部,耦合度较高,
public static class IdShengAgeJiangOrder implements Comparator{ // 根据id从小到大,但是如果id一样,按照年龄从大到小 @Override public int compare(Student o1, Student o2) { return o1.id != o2.id ? (o1.id - o2.id) : (o2.age - o1.age); } } public static void main(String[] args) { Arrays.sort(students, new IdShengAgeJiangOrder()); }
任何比较器:
compare方法里,遵循一个统一的规范:
返回负数的时候,认为第一个参数应该排在前面
返回正数的时候,认为第二个参数应该排在前面
返回0的时候,认为无所谓谁放前面
补充:Collections类是一个包装类,它包含有各种有关集合操作的静态方法。就像一个工具类。
public static void sort(List list,Comparator<>),根据指定比较器产生的顺序对指定列表进行排序,此列表内的所有元素都必须可使用指定的比较器相互比较
package Sort;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.TreeMap;
public class Code01_Comparator {
public static class Student {
public String name;
public int id;
public int age;
public Student(String name, int id, int age) {
this.name = name;
this.id = id;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + ''' +
", id=" + id +
", age=" + age +
'}';
}
}
// 任何比较器:
// compare方法里,遵循一个统一的规范:
// 返回负数的时候,认为第一个参数应该排在前面
// 返回正数的时候,认为第二个参数应该排在前面
// 返回0的时候,认为无所谓谁放前面
public static class IdShengAgeJiangOrder implements Comparator {
// 根据id从小到大,但是如果id一样,按照年龄从大到小
@Override
public int compare(Student o1, Student o2) {
return o1.id != o2.id ? (o1.id - o2.id) : (o2.age - o1.age);
}
}
public static class IdAscendingComparator implements Comparator {
// 返回负数的时候,第一个参数排在前面
// 返回正数的时候,第二个参数排在前面
// 返回0的时候,谁在前面无所谓
@Override
public int compare(Student o1, Student o2) {
return o1.id - o2.id;
}
}
public static class IdDescendingComparator implements Comparator {
@Override
public int compare(Student o1, Student o2) {
return o2.id - o1.id;
}
}
// 先按照id排序,id小的,放前面;
// id一样,age大的,前面;
public static class IdInAgeDe implements Comparator {
@Override
public int compare(Student o1, Student o2) {
return o1.id != o2.id ? o1.id - o2.id : (o2.age - o1.age);
}
}
public static void printStudents(Student[] students) {
for (Student student : students) {
System.out.println("Name : " + student.name + ", Id : " + student.id + ", Age : " + student.age);
}
}
public static void printArray(Integer[] arr) {
if (arr == null) {
return;
}
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
System.out.println();
}
public static class MyComp implements Comparator {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
}
public static class AComp implements Comparator {
// 如果返回负数,认为第一个参数应该拍在前面
// 如果返回正数,认为第二个参数应该拍在前面
// 如果返回0,认为谁放前面都行
@Override
public int compare(Integer arg0, Integer arg1) {
return arg1 - arg0;
// return 0;
}
}
public static void main(String[] args) {
Integer[] arr = { 5, 4, 3, 2, 7, 9, 1, 0 };
Arrays.sort(arr, new AComp());
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
System.out.println("===========================");
Student student1 = new Student("A", 4, 40);
Student student2 = new Student("B", 4, 21);
Student student3 = new Student("C", 3, 12);
Student student4 = new Student("D", 3, 62);
Student student5 = new Student("E", 3, 42);
// D E C A B
Student[] students = new Student[] { student1, student2, student3, student4, student5 };
System.out.println("第一条打印");
Arrays.sort(students, new IdShengAgeJiangOrder());
// for (int i = 0; i < students.length; i++) {
// Student s = students[i];
// System.out.println(s.name + "," + s.id + "," + s.age);
// }
System.out.println(Arrays.toString(students));
System.out.println("第二条打印");
ArrayList studentList = new ArrayList<>();
studentList.add(student1);
studentList.add(student2);
studentList.add(student3);
studentList.add(student4);
studentList.add(student5);
studentList.sort(new IdShengAgeJiangOrder());
for (int i = 0; i < studentList.size(); i++) {
Student s = studentList.get(i);
System.out.println(s.name + "," + s.id + "," + s.age);
}
// N * logN
System.out.println("第三条打印");
student1 = new Student("A", 4, 40);
student2 = new Student("B", 4, 21);
student3 = new Student("C", 4, 12);
student4 = new Student("D", 4, 62);
student5 = new Student("E", 4, 42);
TreeMap treeMap = new TreeMap<>((a, b) -> (a.id - b.id));
treeMap.put(student1, "我是学生1,我的名字叫A");
treeMap.put(student2, "我是学生2,我的名字叫B");
treeMap.put(student3, "我是学生3,我的名字叫C");
treeMap.put(student4, "我是学生4,我的名字叫D");
treeMap.put(student5, "我是学生5,我的名字叫E");
for (Student s : treeMap.keySet()) {
System.out.println(s.name + "," + s.id + "," + s.age);
}
}
}
6.完结撒花


