Java 比较器

• 在 Java 中经常会涉及到对象数组的排序问题,那么就涉及到对象之间的比较问题。
• Java 实现对象排序的方式有两种:
– 自然排序:java.lang.Comparable
– 定制排序:java.util.Comparator

5.1 自然排序:java.lang.Comparable
• Comparable 接口强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序。
• 实现 Comparable 的类必须实现 compareTo(Object obj)方法,两个对象即通过compareTo(Object obj) 方法的返回值来比较大小。
如果当前对象 this 大于形参对象obj,则返回正整数,
如果当前对象 this 小于形参对象 obj,则返回负整数,
如果当前对象 this 等于形参对象 obj,则返回零。

package java.lang;
public interface Comparable{
 int compareTo(Object obj);
}

• 实现 Comparable 接口的对象列表(和数组)可以通过 Collections.sort 或Arrays.sort 进行自动排序。实现此接口的对象可以用作有序映射中的键或有序集合中的元素,无需指定比较器。
• 对于类 C 的每一个 e1 和 e2 来说,当且仅当 e1.compareTo(e2) == 0 与
e1.equals(e2) 具有相同的 boolean 值时,类 C 的自然排序才叫做与 equals 一致。建议(虽然不是必需的)最好使自然排序与 equals 一致。
• Comparable 的典型实现:(默认都是从小到大排列的)
– String:按照字符串中字符的 Unicode 值进行比较
– Character:按照字符的 Unicode 值来进行比较
– 数值类型对应的包装类以及 BigInteger、BigDecimal:按照它们对应的数值大小进行比较
– Boolean:true 对应的包装类实例大于 false 对应的包装类实例
– Date、Time 等:后面的日期时间比前面的日期时间大
• 代码示例:

package com.atguigu.api;
public class Student implements Comparable {
 private int id;
 private String name;
 private int score;
 private int age;
 public Student(int id, String name, int score, int age) {
 this.id = id;
 this.name = name;
 this.score = score;
 this.age = age;
 }
 public int getId() {
 return id;
 }
 public void setId(int id) {
 this.id = id;
 }
 public String getName() {
 return name;
 }
 public void setName(String name) {
 this.name = name;
 }
 public int getScore() {
 return score;
 }
 public void setScore(int score) {
 this.score = score;
 }
 public int getAge() {
 return age;
 }
 public void setAge(int age) {
 this.age = age;
 }
 @Override
 public String toString() {
 return "Student{" +
 "id=" + id +
 ", name='" + name + '\'' +
 ", score=" + score +
 ", age=" + age +
 '}';
 }
 @Override
 public int compareTo(Object o) {
 //这些需要强制,将 o 对象向下转型为 Student 类型的变量,才能调用 Student 类中的属性
 //默认按照学号比较大小
 Student stu = (Student) o;
 return this.id - stu.id;
 }
}

测试类

package com.atguigu.api;
public class TestStudent {
 public static void main(String[] args) {
 Student[] arr = new Student[5];
 arr[0] = new Student(3,"张三",90,23);
 arr[1] = new Student(1,"熊大",100,22);
 arr[2] = new Student(5,"王五",75,25);
 arr[3] = new Student(4,"李四",85,24);
 arr[4] = new Student(2,"熊二",85,18);
 //单独比较两个对象
 System.out.println(arr[0].compareTo(arr[1]));
 System.out.println(arr[1].compareTo(arr[2]));
 System.out.println(arr[2].compareTo(arr[2]));
 System.out.println("所有学生:");
 for (int i = 0; i < arr.length; i++) {
 System.out.println(arr[i]);
 }
 System.out.println("按照学号排序:");
 for (int i = 1; i < arr.length; i++) {
 for (int j = 0; j < arr.length-i; j++) {
 if(arr[j].compareTo(arr[j+1])>0){
 Student temp = arr[j];
 arr[j] = arr[j+1];
 arr[j+1] = temp;
 }
 }
 }
 for (int i = 0; i < arr.length; i++) {
 System.out.println(arr[i]);
 }
 }
}

再举例:

public class Student implements Comparable {
 private String name;
 private int score;
 public Student(String name, int score) {
 this.name = name;
 this.score = score;
 }
 public String getName() {
 return name;
 }
 public void setName(String name) {
 this.name = name;
 }
 public int getScore() {
 return score;
 }
 public void setScore(int score) {
 this.score = score;
 }
 @Override
 public String toString() {
 return "Student{" +
 "name='" + name + '\'' +
 ", score=" + score +
 '}';
 }
 @Override
 public int compareTo(Object o) {
 return this.score - ((Student)o).score;
 }
}
测试:
@Test
public void test02() {
Student[] students = new Student[3];
students[0] = new Student("张三", 96);
students[1] = new Student("李四", 85);
students[2] = new Student("王五", 98);
System.out.println(Arrays.toString(students));
Arrays.sort(students);
System.out.println(Arrays.toString(students));
}

再举例:

class Goods implements Comparable {
 private String name;
 private double price;
 //按照价格,比较商品的大小
 @Override
 public int compareTo(Object o) {
 if(o instanceof Goods) {
 Goods other = (Goods) o;
 if (this.price > other.price) {
 return 1;
 } else if (this.price < other.price) {
 return -1;
 }
 return 0;
 }
 throw new RuntimeException("输入的数据类型不一致");
 }
 //构造器、getter、setter、toString()方法略
}

测试:

public class ComparableTest{
 public static void main(String[] args) {
 Goods[] all = new Goods[4];
 all[0] = new Goods("《红楼梦》", 100);
 all[1] = new Goods("《西游记》", 80);
 all[2] = new Goods("《三国演义》", 140);
 all[3] = new Goods("《水浒传》", 120);
 Arrays.sort(all);
 System.out.println(Arrays.toString(all));
 }
}

5.2 定制排序:java.util.Comparator
• 思考
– 当元素的类型没有实现 java.lang.Comparable 接口而又不方便修改代码
(例如:一些第三方的类,你只有.class 文件,没有源文件)
– 如果一个类,实现了 Comparable 接口,也指定了两个对象的比较大小的规则,但是此时此刻我不想按照它预定义的方法比较大小,但是我又不能随意修改,因为会影响其他地方的使用,怎么办?
• JDK 在设计类库之初,也考虑到这种情况,所以又增加了一个 java.util.Comparator 接口。强行对多个对象进行整体排序的比较。
– 重写 compare(Object o1,Object o2)方法,比较 o1 和 o2 的大小:如果方法返回正整数,则表示 o1 大于 o2;如果返回 0,表示相等;返回负整数,表示 o1 小于 o2。
– 可以将 Comparator 传递给 sort 方法(如 Collections.sort 或
Arrays.sort),从而允许在排序顺序上实现精确控制。

package java.util;
public interface Comparator{
 int compare(Object o1,Object o2);
}

举例:

package com.atguigu.api;
import java.util.Comparator;
//定义定制比较器类
public class StudentScoreComparator implements Comparator {
 @Override
 public int compare(Object o1, Object o2) {
 Student s1 = (Student) o1;
 Student s2 = (Student) o2;
 int result = s1.getScore() - s2.getScore();
 return result != 0 ? result : s1.getId() - s2.getId();
 }
}

测试类

package com.atguigu.api;
public class TestStudent {
 public static void main(String[] args) {
 Student[] arr = new Student[5];
 arr[0] = new Student(3, "张三", 90, 23);
 arr[1] = new Student(1, "熊大", 100, 22);
 arr[2] = new Student(5, "王五", 75, 25);
 arr[3] = new Student(4, "李四", 85, 24);
 arr[4] = new Student(2, "熊二", 85, 18);
 System.out.println("所有学生:");
 for (int i = 0; i < arr.length; i++) {
 System.out.println(arr[i]);
 }
 System.out.println("按照成绩排序");
 StudentScoreComparator sc = new StudentScoreComparator();
 for (int i = 1; i < arr.length; i++) {
 for (int j = 0; j < arr.length - i; j++) {
 if (sc.compare(arr[j], arr[j + 1]) > 0) {
 Student temp = arr[j];
 arr[j] = arr[j + 1];
 arr[j + 1] = temp;
 }
 }
 }
 for (int i = 0; i < arr.length; i++) {
 System.out.println(arr[i]);
 }
 }
}

再举例:

@Test
public void test01() {
 Student[] students = new Student[5];
 students[0] = new Student(3, "张三", 90, 23);
 students[1] = new Student(1, "熊大", 100, 22);
 students[2] = new Student(5, "王五", 75, 25);
 students[3] = new Student(4, "李四", 85, 24);
 students[4] = new Student(2, "熊二", 85, 18);
 System.out.println(Arrays.toString(students));
 //定制排序
 StudentScoreComparator sc = new StudentScoreComparator();
 Arrays.sort(students, sc);
 System.out.println("排序之后:");
 System.out.println(Arrays.toString(students));
}

再举例:

Goods[] all = new Goods[4];
all[0] = new Goods("War and Peace", 100);
all[1] = new Goods("Childhood", 80);
all[2] = new Goods("Scarlet and Black", 140);
all[3] = new Goods("Notre Dame de Paris", 120);
Arrays.sort(all, new Comparator() {
 @Override
 public int compare(Object o1, Object o2) {
 Goods g1 = (Goods) o1;
 Goods g2 = (Goods) o2;
 return g1.getName().compareTo(g2.getName());
 }
});
System.out.println(Arrays.toString(all));

你可能感兴趣的:(java,数据结构,算法)