Comparatable接口和Comparator接口的使用与区别

这篇博文可以为你解决的问题如下:
  1. 什么是自然排序
  2. Collections.sort()与Arrays.sort()的异同点
  3. Comparatable接口和Comparator接口各自的排序依据(理论讲解)
  4. Comparatable接口和Comparator接口实用排序方法(实际例子分析)
  5. 综合使用Comparatable和Comparator进行整体排序
以下,我就根据上面的问题来写这篇博文:

1、什么是自然排序

    自然排序是一种 升序排序。对于不同的数据类型,升序规则不一样:
  • BigDecimal BigInteger Byte Double Float Integer Long Short 类型,是按照数值的大小进行排序的。例如:12<23, 111.111>3.23
  • Character及String类型,是按照各个字符的Unicode值大小来排序的。例如:"3BC"<"AB"<"aBC"<"一二"

2、Collections.sort()与Arrays.sort()的异同点


首先,我们来看一下这两个方法的定义:
  • Collections.sort()://它的定义只有以下两个
public static   Comparable > void sort ( List  list);
public static  void sort(List list, Comparator c);
  • Arrays.sort()://它的定义有很多,这里列出有代表性的三个
public static void sort(int[] a);
public static void sort(Object[] a);
public static void sort(T[] a,  Comparator  c) ;

从它们的定义中,我们可以看出两点:
  1. 不同点:它们适用对象不一样。
  • Collections.sort()仅适用于列表型
  • Arrays.sort()仅适用数组类型,当然数组可以是int、float等,甚至可以是Object对象。
  2. 共同点:它们直接或间接地使用Comparatable接口或Comparator接口。
  • Collections.sort()很明显地引用了这两个接口,这里就不细说了;
  • Arrays.sort()中,其实,int、float等对应的封装类Integer、Float等class中,都有实现对接口Comparable的引用,例如:Integer的定义如下:
    public final class Integer
    extends  Number
    implements  Comparable< Integer>
    Comparable接口在默认情况下,具有自然排序功能。所以,当我们使用Arrays.sort(int[])时,就已经实现了对int[]进行自然排序的功能了。

3、Comparatable接口和Comparator接口各自的排序依据
引言:
    既然是排序,那就需要指定序依元素,且只要指定了排序依据元素,并且调用的方法得当,那么一定可以成功排序。 (请牢牢记住这句话)
  • 对于元素的类,例如:int、float、double、char、String等数据类型,排序依据元素就是它相应的这个单元素。
  • 对于元素的类,例如:我们自定义一个Student类,它的属性有int age;String name;等,那么我们就需要指定一个排序依据元素
Comparable接口的排序依据:
  • 单元素类排序。(一般是指Java中已经实现Comparable接口的类,常用的有:Integer、Float、Double、String、Character等),这些类已经有了排序依据元素,所以可以直接排序。因此,在排序中,我们可以这样做:(以int为例)
         int[] intArray = {12,34,0,5,-7,8,1,3};
               Arrays.sort(intArray); //这里就是直接依据int值的大小来排序的
     
      for(int i=0;i
               System.out.println(intArray[i]);
      程序运行的结果是:(自然排序)
               Comparatable接口和Comparator接口的使用与区别
  • 多元素类排序。

       首先,需要进行排序的这个多元素类(如:Student)必须实现Comparable接口,且T为该多元素类的类名。
             例如:
public static Student implments Comparable
       然后,在该类中(一定要在该内的内部)实现comparaTo()方法,在这里,我们将指定排序依据元素。
             例如:

             @Override
              public int compareTo(Student arg0) {
                  return arg0.getName().compareTo(this.name); //这里我们指定name为排序依据元素
              }
       最后,根据Student实例化时,是用List、还是Student[]来实现的,选择使用 Collection.sort()或Arrays.sort()进行排序。
Comparator接口的排序依据:
    与Comparable不同的是,要实现Comparator接口,一定要在程序中指定排序依据元素(不管是单元素,还是多元素)。而且,这个实现Comparator接口的类一定要在排序的类(如Student)之外。可以是匿名类,如:
Collection.sort(allStudents,new Comparator() {
    public int compare(Student one, Student another) {
        return one.getAge() - another.getAge();
    }
});
也可以是一个外部类,如class StudentSort implments{};的实例,Collention.sort(allStudent,new StudentSort());
小结:Comparatable接口必须由需要排序的多元素类本身来实现,且在其内部重写comparaTo()方法;Comparator接口是在需要排序的多元素类的外部 (即使用外部类)来实现,且必须在该外部类中重写compara()方法。

4、Comparatable接口和Comparator接口实用排序方法(实际例子分析)

现在我们将用学生信息系统的排序来讲解:
  • 类名:Student
  • 属性值:long ID;String name;int age;float score;
  • 要求:根据学号、姓名或成绩升序排序所有Student实例
下面两种方法中,橘红色部分为两种方法不同的地方。
一、使用Camparable接口(共2个文件,按学号进行升序排序)

package keNan.com.stu.StudentInfomation;

public class Student implements Comparable{  
    private String ID;
    private String name;
    private int age;
    private double score;
  
    //为Student定义两个构造方法


    public Student(String ID, String name) {
        this(ID,name,0,0);
    }
    public Student(String ID, String name, int age, double score){
        this.ID = ID;
        this.name = name;
        this.age = age;
        this.score = score;
    }
   
    //属性值访问与修改
    public String getID(){
        return ID;
    }
    public String getName(){
        return name;
    }
    public int getAge(){
        return age;
    }
    public double getScore(){
        return score;
    }
  
    public void setID(String newID){
        ID = newID;
    }
    public void setName(String newName){
        name = newName;
    }
    public void setAge(int newAge){
        if(newAge < 0)
            newAge = 0;
        age = newAge;
    }
    public void setScore(double newScore){
        if( (newScore < 0 )||(newScore > 100))
            newScore = 0;
        score = newScore;
    }
   
    //重写对象字符串表示方法
    @Override
    public String toString() {
        String info = new String();
        info = ID + '\t' + name + '\t' + age + '\t' + score + '\n';
        return info;
    }

    @Override
    public int compareTo(Student arg0) {
        return this.ID.compareTo(arg0.ID);//此种写法为升序,若改为arg0.ID.compareTo(this.ID)则为降序
    }
}

package keNan.com.stu.StudentInfomation;

import java.util.Arrays;

public class StudentManage{
    public static void main(String[] args){
        //定义一个学生数据库
        final int STUDENT_NUM = 4;
        Student[] allStudents = new Student[STUDENT_NUM];
      
        //初始化学生数据库
        allStudents[0] = new Student("00001","a");
        allStudents[1] = new Student("00003","b");
        allStudents[2] = new Student("00002","c");
        allStudents[3] = new Student("00004","d");
        for(int i=0;i
            allStudents[i].setAge(i*10);
        }
        for(int i=0;i
            allStudents[i].setScore(99 - i*1.5);
        }
      
        //按学号升序排序
        Arrays.sort(allStudents);
       
        //显示学生信息
        System.out.println("学号" + "\t姓名" + "\t年龄" + "\t成绩");
        for(int i=0;i
            System.out.print(allStudents[i]);
        }
    }
}
程序运行结果:
Comparatable接口和Comparator接口的使用与区别

二、使用Camparator接口(共2个文件,先按姓名升序进行排序,再成绩降序排序)

package keNan.com.stu.StudentInfomation;

public class Student{  
    private String ID;
    private String name;
    private int age;
    private double score;
  
    //为Student定义两个构造方法
    public Student(String ID, String name) {
        this(ID,name,0,0);
    }
    public Student(String ID, String name, int age, double score){
        this.ID = ID;
        this.name = name;
        this.age = age;
        this.score = score;
    }
   
    //属性值访问与修改
    public String getID(){
        return ID;
    }
    public String getName(){
        return name;
    }
    public int getAge(){
        return age;
    }
    public double getScore(){
        return score;
    }
   
    public void setID(String newID){
        ID = newID;
    }
    public void setName(String newName){
        name = newName;
    }
    public void setAge(int newAge){
        if(newAge < 0)
            newAge = 0;
        age = newAge;
    }
    public void setScore(double newScore){
        if( (newScore < 0 )||(newScore > 100))
            newScore = 0;
        score = newScore;
    }
   
    //重写对象字符串表示方法
    @Override
    public String toString() {
        String info = new String();
        info = ID + '\t' + name + '\t' + age + '\t' + score + '\n';
        return info;
    }
}

package keNan.com.stu.StudentInfomation;

import java.util.Arrays;
import java.util.Comparator;

public class StudentManage{
    public static void main(String[] args){
        //定义一个学生数据库



        final int STUDENT_NUM = 4;

        Student[] allStudents = new Student[STUDENT_NUM];
       
        //初始化学生数据库
        allStudents[0] = new Student("00001","a");
        allStudents[1] = new Student("00003","b");
        allStudents[2] = new Student("00002","c");
        allStudents[3] = new Student("00004","d");
        for(int i=0;i
            allStudents[i].setAge(i*10);
        }

        for(int i=0;i
            allStudents[i].setScore(99 - i*1.5);
        }
       
        //按姓名升序排序
        Arrays.sort(allStudents,new ComparatorWithNameUP());
       
        //显示学生信息

        System.out.println("学号" + "\t姓名" + "\t年龄" + "\t成绩");
        for(int i=0;i
            System.out.print(allStudents[i]);
        }
       
        //按成绩降序排序
        Arrays.sort(allStudents,new ComparatorWithScoreDown());
       
        //显示学生信息

        System.out.println("学号" + "\t姓名" + "\t年龄" + "\t成绩");
        for(int i=0;i
            System.out.print(allStudents[i]);
        }
    }
}

//按姓名进行升序排序的外部类,用Comparator接口
class ComparatorWithNameUP implements Comparator{

    @Override
    public int compare(Student arg0, Student arg1) {

        // TODO Auto-generated method stub
        return arg0.getName().compareTo(arg1.getName());
    }   
}

//按成绩降序

class ComparatorWithScoreDown implements Comparator{

    @Override
    public int compare(Student arg0, Student arg1) {
        // TODO Auto-generated method s
tub
        if(arg1.getScore() > arg0.getScore())
            return 1;
        else {
            if(arg1.getScore() == arg0.getScore())
                return 0;
            else return -1;
        }
    }
   
}

程序运行结果:
Comparatable接口和Comparator接口的使用与区别

5、综合使用Comparatable和Comparator进行整体排序

Comparable:
  • 优点是,对于单元素集合可以实现直接自然排序;
  • 缺点是,对于多元素排序,它的排序依据元素是固定的(compareTo()抽象方法只能实现一次),因此排序方式固定。
Comparator:
  • 优点是,元素的排序依据元素是可变的,因为可以定义N多个外部类,每个外部类实现一种排序。在不同需求下,选择不同的排序。
  • 缺点是,无论是多元素,还是单元素,都必须自己创建一个外部类来实现排序。
     所以在实际运用当中,可以用Comparable的compareTo()方法来定义默认排序方式,用Comparator定义其他排序方式。
    还有一点要注意,即使Student类已经implements Comparable,但是我们在自定义外部类,如
class ComparatorWithNameUP implements Comparator,并在排序时引用sort(allStudents,new ComparatorWithNameUp());生效的排序算法是ComparatorWithNameUp.
参考资料:
  1. Comparator和Comparable比较
  2. Comparable 与 Comparator 两个接口的作用
  3. 使用TreeSet集合比较Comparable接口和Comparator接口的区别

你可能感兴趣的:(java基础)