• 夯实Java基础(十五)——Java中Comparable和Comparator


    1、前言

    对于Java中的对象,我们只能使用基本运算符==、!=来判断一下地址是否相等,不能使用>、<来比较大小。但是在实际的开发中,我们需要对对象进行排序,也就是比较大小,那么应该如何实现呢?这就涉及到了Java中的两个常用的接口Comparable<T>和Comparator<T>的实现了。下面通过示例学习这两个接口的使用。

    2、Comparable接口

    Comparable是一个基于排序接口,它是自然排序。该接口中只有一个compareTo(Obj o)方法,用于给一个类的多个实例比较大小,进而完成排序。也就是说某个类实现了Comparable接口,就意味着该类支持排序。通过实现类重写compareTo(Obj o)方法,从而规定多个实例的自然顺序,然后使用Arrays.sort 或Collections.sort 方法对数组对象或List对象进行排序。

    用String举一个简单的例子:

    1 public class CompareTest {
    2     public static void main(String[] args) {
    3         String[] str=new String[]{"AA","EE","DD","CC","FF","BB"};
    4         Arrays.sort(str);
    5         System.out.println(Arrays.toString(str));
    6     }
    7 }

    运行结果为:

    可以发现,在使用Arrays.sort(str)之后就完成了排序,但是我们并没有调用compareTo(Obj o)方法。我们知道String源码中实现了Comparable接口并且重写该接口的方法,在使用Arrays.sort(str)时sort方法内部间接的调用了String的compareTo(Obj o)方法,所以我们直接就看到了排序的结果。像String、包装类等实现了Comparable接口,重写了compareTo方法,都清晰的给出了比较两个对象的方式,可以自行去看一下String重写的compareTo方法的源码。但是在重写compareTo(Obj o)方法时都需要遵循这三个规则:

    ①、如果比较者(即this当前对象)大于被比较者(即compareTo方法里面的形参),则返回正整数。

    ②、如果比较者小于被比较者,那么返回负整数。

    ③、如果比较者等于被比较者,那么返回零。

    自定义的类是无法排序的,但是通过实现Comparable接口之后就可以实现,然后通过Arrays.sort 或Collections.sort 方法排序。我们来看一个自己定义的类怎么使用Comparable接口进行排序:

     1 public class Person  implements Comparable{
     2     private String name;
     3     private int age;
     4 
     5     public Person(String name, int age) {
     6         this.name = name;
     7         this.age = age;
     8     }
     9 
    10     public String getName() {
    11         return name;
    12     }
    13 
    14     public void setName(String name) {
    15         this.name = name;
    16     }
    17 
    18     public int getAge() {
    19         return age;
    20     }
    21 
    22     public void setAge(int age) {
    23         this.age = age;
    24     }
    25 
    26     //按名字排序
    27     @Override
    28     public int compareTo(Object o) {
    29         if(o instanceof Person){
    30             Person p= (Person) o;
    31             //name是String类型,这里直接调用String的compareTo
    32             if (this.name.compareTo(p.name)>0){
    33                 return 1;
    34             }else if(this.name.compareTo(p.name)<0){
    35                 return -1;
    36             }else{
    37                 return 0;
    38             }
    39         }else{
    40             throw new RuntimeException("传入数据类型不一致...");
    41         }
    42     }
    43 
    44     public static void main(String[] args) {
    45         Person[] p=new Person[5];
    46         p[0]=new Person("Jack",23);
    47         p[1]=new Person("Marry",13);
    48         p[2]=new Person("Tom",18);
    49         p[3]=new Person("John",33);
    50         p[4]=new Person("Thomas",41);
    51         System.out.println("排序前------------");
    52         for (Person person : p) {
    53             System.out.print(person.getName()+":"+person.getAge()+"
    ");
    54         }
    55         System.out.println("排序后------------");
    56         Arrays.sort(p);
    57         for (Person person : p) {
    58             System.out.print(person.getName()+":"+person.getAge()+"
    ");
    59         }
    60     }
    61 }

    运行结果为:

    在Person类中实现了Comparable接口并且重写compareTo(Obj o)方法,然后我们按照名字排序,可以发现它默认的排序方式是升序,如果要降序则可以在返回值前面加一个负号。

    3、Comparator接口

    Comparator也是一个排序接口,它和Comparable功能是一样的,但是它是定制排序。怎么来理解定制排序呢?如果某个类没有实现Comparable接口,而该类本身是不支持排序的,那么我们就可以使用Comparator来进行排序,或者我们自定义类实现了Comparable接口后,但是自定义类的代码不能再更改了,这时需要改变comparaTo(Obj o)方法中排序的方式,此时也可以选择定制排序Comparator。Comparator接口中有一个compare(T o1, T o2)方法和compareTo(Obj o)类似,定义排序的规则一样:

    o1>o2,返回值为正整数。

    o1<o2,返回值为负整数。

    o1=o2,返回值为零。

    同样使用String简单举例:

     1 public class CompareTest {
     2     public static void main(String[] args) {
     3         String[] str=new String[]{"AA","EE","DD","CC","FF","BB"};
     4         //使用匿名内部类直接创建
     5         Arrays.sort(str, new Comparator<String>() {
     6             @Override
     7             public int compare(String o1, String o2) {
     8                 if (o1.compareTo(o2)>0){
     9                     return 1;
    10                 }else if (o1.compareTo(o2)<0){
    11                     return -1;
    12                 }else{
    13                     return 0;
    14                 }
    15             }
    16         });
    17         System.out.println(Arrays.toString(str));
    18     }
    19 }

    我们知道接口是不能被实例化的,这里是匿名内部类的知识,可以自行去度娘寻找答案。

    自定义类使用Comparator进行排序:

     1 public class Person{
     2     private String name;
     3     private int age;
     4 
     5     public Person(String name, int age) {
     6         this.name = name;
     7         this.age = age;
     8     }
     9 
    10     public String getName() {
    11         return name;
    12     }
    13 
    14     public void setName(String name) {
    15         this.name = name;
    16     }
    17 
    18     public int getAge() {
    19         return age;
    20     }
    21 
    22     public void setAge(int age) {
    23         this.age = age;
    24     }
    25 
    26     public static void main(String[] args) {
    27         Person[] p=new Person[5];
    28         p[0]=new Person("Jack",23);
    29         p[1]=new Person("Marry",13);
    30         p[2]=new Person("Tom",18);
    31         p[3]=new Person("John",33);
    32         p[4]=new Person("Thomas",41);
    33         System.out.println("排序前------------");
    34         for (Person person : p) {
    35             System.out.print(person.getName()+":"+person.getAge()+"
    ");
    36         }
    37         System.out.println("排序后------------");
    38         Arrays.sort(p, new Comparator<Person>() {
    39             //按照年龄默认排序,如果年龄相同则按照名字默认排序
    40             @Override
    41             public int compare(Person o1, Person o2) {
    42                 if (o1 instanceof Person && o2 instanceof Person) {
    43                     if (o1.age > o2.age) {
    44                         return 1;
    45                     }else if (o1.age<o2.age){
    46                         return -1;
    47                     }else   {
    48                         return o1.name.compareTo(o2.name);
    49                     }
    50                 }else{
    51                     throw new RuntimeException("传入数据类型不一致...");
    52                 }
    53             }
    54         });
    55         for (Person person : p) {
    56             System.out.print(person.getName()+":"+person.getAge()+"
    ");
    57         }
    58     }
    59 }

    程序运行结果:

    这样就使用Comparator定制排好序了。

    4、小结

    小结一下Comparable和Comparator的使用和区别:

    ①、Comparable是java.lang包下的,而Comparator是java.util包下的。

    ②、Comparable可以看做是内部比较器,而Comparator是外部比较器。

    ③、Comparable是自然排序,Comparator是定制排序。

    ④、如果某个类没有实现Comparable接口,而该类本身是不支持排序的,那么我们就可以使用Comparator来进行定制排序。

    ⑤、或者我们自定义类实现了Comparable接口后,但是自定义类的代码不能再更改了,这时需要改变compareTo(Obj o)方法中排序的方式,此时也可以选择定制排序Comparator。

    这两种方法各有优劣:某个类实现了Comparable接口后,在任何地方都可以比较大小,但是有时候需要修改其比较的方式,则需要修原有的代码。而用Comparator的好处就是不需要修改原有代码, 而是另外实现一个比较器, 当某个自定义的对象需要作比较的时候,把比较器和对象一起传递过去就可以比大小了, 并且在Comparator 里面用户可以自己实现复杂的可以通用的逻辑,使其可以匹配一些比较简单的对象,那样就可以节省很多重复劳动了。

  • 相关阅读:
    Java多线程、并发
    Java I/O系统
    Java注解
    Arthas(Java诊断工具)
    Java泛型
    Java内部类
    libpcap使用
    python文件服务器
    设计模式
    protobuf
  • 原文地址:https://www.cnblogs.com/tanghaorong/p/11310786.html
Copyright © 2020-2023  润新知