Java : Comparable 和 Comparator 接口

对象排序

例如我已经有如下的 Person 类,该类具有 name 和 age 2 个属性,现在我们需要对存放 Person 类的数组或集合进行排序。此时有很多的排序策略,例如对 age 按升序或降序排序,或堆 name 按字典序排序,也可以先按 age 进行排序后对 age 属性相同的对象按 name 的字典序排序。

class Person{
	private String name;
	private int age;
	
	public PersonSortable(String name,int age){
		this.name = name;
		this.age = age;
	}

	@Override
	public String toString() {
		return name + "-" + age;
	}
}

之前用 C 语言解决问题,需要分别写多个函数,每个函数根据不同的规则运行排序算法。但是由于 Java 的接口技术,因此可以使用 sort() 享受快速排序的快感,这就要求被排序的类实现了对应的接口,常用的支持排序的接口有 Comparable 接口和 Comparator 接口。

Comparable 接口

compare() 方法

想要对实例化的对象进行快速排序,前提条件是这个对象是可比较的,例如数字可以按照数值的大小进行排序,而字符可以根据字典序进行排序。而对于一个对象来说,往往这个对象会具有很多属性,这就导致了对对象的排序不能简单地按照大小之类的规则来进行。换言之,个人理解的 Comparable 接口标志了这个类是可比较的,而 compare() 方法界定了这个类的比较规则。当时用 Collections.sort 和 Arrays.sort 进行排序时,就需要参考 compare() 方法定义的规则进行排序。
Comparable 接口指定了类将实现 compare(T o1, T o2) 方法,该方法将定义实例化的对象的比较规则。传入的参数 o1 为要比较的第一个对象,o2 为要比较的第二个对象,根据第一个参数小于、等于或大于第二个参数分别返回负整数、零或正整数。类实现 Comparable 接口后,该对象的列表(和数组)可以通过 Collections.sort 和 Arrays.sort 进行自动排序。

JDK 文档

Comparable 接口

compare() 方法

实例

例如将上文的 Person 类实现 Comparable 接口,compareTo 方法实现先对 name 属性进行字典序升序排序,如果 name 相同则对 age 进行升序排序。

import java.util.*;

class Person implements Comparable<Person>{
	private String name;
	private int age;
	
	public PersonSortable(String name,int age){
		this.name = name;
		this.age = age;
	}

	@Override
	public String toString() {
		return name + "-" + age;
	}
	
	public int compareTo(PersonSortable obj) {
        if(this.name.compareTo(obj.name) != 0){
        	return this.name.compareTo(obj.name);
        }
        if(this.age == obj.age){
        	return 0;
        }
        if(this.age > obj.age){
        	return 1;
        }
        else{
        	return -1;
        }
    }
}

值的一提的是 String 类也实现了 Comparable 接口,因此可以调用其 compareTo 方法实现按照字典序排序。接下来写个 mian 方法进行测试:

public static void main(String args[]){

      Person array[] = new Person[5];
      array[0] = new Person("zhang", 15);
      array[1] = new Person("zhang", 12);
      array[2] = new Person("wang", 14);
      array[3] = new Person("wang", 17);
      array[4] = new Person("li", 17);

      Arrays.sort(array);
      for(int i = 0; i < fre; i++){
            System.out.println(array[i].toString());
      }
      System.out.println(Arrays.toString(PersonSortable.class.getInterfaces()));
}

Comparator 接口

compare() 方法

如果类实现了 Comparable 方法,则该类进行比较的方式就被严格定下来了,但是在实际运用中可能需要让这个类支持多种排序的方式。此时可以引入 Comparator 接口实现这一点,不过 Comparator 接口并非实现在需要被排序的类上,而是用于实现比较器——用于指定比较规则的类。
此时就不难解释为什么 Comparator 接口可以让类的排序支持多种排序方式了,因为可以写多个实现 Comparator 接口的方法的类,让这些不同的类对应不同的排序规则,用于界定排序规则的是 compare() 方法。此时就可以根据实际的需要,传入对应的实现 Comparator 接口的类给 sort 方法进行排序。

JDK 文档

Comparator 接口

compare() 方法

实例

例如将上文的 Person 类需要支持按 age 属性升序排序和按 name 属性的字典序排序 2 种排序规则,这就需要分别写 2 个实现 Comparator 接口的类来支持。

//NameComparator 类定义了 Person 对象按照 name 属性排序的规则
class NameComparator implements Comparator<Person>{
	public int compare(Person obj1, Person obj2){
		return obj1.getName().compareTo(obj2.getName());
	}
	
}

//AgeComparator 类定义了 Person 对象按照 age 属性排序的规则
class AgeComparator implements Comparator<Person>{
	public int compare(Person obj1, Person obj2){
		return obj1.getAge() - obj2.getAge();
	}
}

写个 mian 方法进行测试:

public static void main(String args[]){

      Person array[] = new Person[5];
      array[0] = new Person("zhang", 15);
      array[1] = new Person("zhang", 12);
      array[2] = new Person("wang", 14);
      array[3] = new Person("wang", 17);
      array[4] = new Person("li", 17);

      //对 name 属性进行排序
      Arrays.sort(array,new NameComparator());    //对 sort 方法传入 NameComparator 对象
      System.out.println("NameComparator:sort");
      for(int i = 0; i < fre; i++){
            System.out.println(array[i].toString());
      }
      
      //对 age 属性进行排序
      Arrays.sort(array,new AgeComparator());    //对 sort 方法传入 AgeComparator 对象
      System.out.println("AgeComparator:sort");
      for(int i = 0; i < fre; i++){
            System.out.println(array[i].toString());
      }
      System.out.println(Arrays.toString(NameComparator.class.getInterfaces()));
      System.out.println(Arrays.toString(AgeComparator.class.getInterfaces()));
}

参考资料

Java第04次实验提纲(面向对象2-继承、多态、抽象类与接口)

原文地址:https://www.cnblogs.com/linfangnan/p/14267643.html