java比较器Comparable接口和Comaprator接口

java的比较器有两类,分别是Comparable接口和Comparator接口。

在为对象数组进行排序时,比较器的作用非常明显,首先来讲解Comparable接口。

让需要进行排序的对象实现Comparable接口,重写其中的compareTo(T o)方法,在其中定义排序规则,那么就可以直接调用java.util.Arrays.sort()来排序对象数组,实例如下:

复制代码
class Student implements Comparable<Student>{
    private String name;
    private int age;
    private float score;
    
    public Student(String name, int age, float score) {
        this.name = name;
        this.age = age;
        this.score = score;
    }
    
    public String toString()
    {
        return name+"\t\t"+age+"\t\t"+score;
    }

    @Override
    public int compareTo(Student o) {
        // TODO Auto-generated method stub
        if(this.score>o.score)//score是private的,为什么能够直接调用,这是因为在Student类内部
            return -1;//由高到底排序
        else if(this.score<o.score)
            return 1;
        else{
            if(this.age>o.age)
                return 1;//由底到高排序
            else if(this.age<o.age)
                return -1;
            else
                return 0;
        }
    }
}

public class ComparableDemo01 {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Student stu[]={new Student("zhangsan",20,90.0f),
                new Student("lisi",22,90.0f),
                new Student("wangwu",20,99.0f),
                new Student("sunliu",22,100.0f)};
        java.util.Arrays.sort(stu);
        for(Student s:stu)
        {
            System.out.println(s);
        }
    }
}
复制代码

程序运行结果:

sunliu 22 100.0
wangwu 20 99.0
zhangsan 20 90.0
lisi 22 90.0

但是在设计类的时候,往往没有考虑到让类实现Comparable接口,那么我们就需要用到另外的一个比较器接口Comparator。

从上面的实例我们可以发现,compareTo(T o)只有一个参数,而Comparator接口中必须要实现的compare(T o1,T o2)就有两个参数。

代码实例:

复制代码
package edu.sjtu.ist.comutil;

import java.util.Comparator;

class Student {
    private String name;
    private int age;
    private float score;
    
    public Student(String name, int age, float score) {
        this.name = name;
        this.age = age;
        this.score = score;
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public float getScore() {
        return score;
    }
    public void setScore(float score) {
        this.score = score;
    }

    public String toString()
    {
        return name+"\t\t"+age+"\t\t"+score;
    }

}

class StudentComparator implements Comparator<Student>{

    @Override
    public int compare(Student o1, Student o2) {
        // TODO Auto-generated method stub
        if(o1.getScore()>o2.getScore())
            return -1;
        else if(o1.getScore()<o2.getScore())
            return 1;
        else{
            if(o1.getAge()>o2.getAge())
                return 1;
            else if(o1.getAge()<o2.getAge())
                return -1;
            else 
                return 0;
        }
    }
    
}


public class ComparableDemo02 {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub

        Student stu[]={new Student("zhangsan",20,90.0f),
                new Student("lisi",22,90.0f),
                new Student("wangwu",20,99.0f),
                new Student("sunliu",22,100.0f)};
        java.util.Arrays.sort(stu,new StudentComparator());
        for(Student s:stu)
        {
            System.out.println(s);
        }
    }

}
复制代码


上述程序的运行结果与代码实例1一样。

比较器还可以用匿名内部类实现

<span style="font-size:14px;">        Arrays.sort(stu,new Comparator<Student>(){

			public int compare(Student o1, Student o2) {
				if(o1.getScore()>o2.getScore())
		            return -1;
		        else if(o1.getScore()<o2.getScore())
		            return 1;
		        else{
		            if(o1.getAge()>o2.getAge())
		                return 1;
		            else if(o1.getAge()<o2.getAge())
		                return -1;
		            else 
		                return 0;
		        }
		}  	
        });</span>


Java排序之Comparable接口和Comparator接口的比较和应用示例

一、其实很简单,单从字面理解就基本明白
1. Comparable:“可比较的”,(欲参与比较的对象对应的元素类需实现Comparable接口)

使用这种策略来比较时,两个对象(这里两个对象是指一个类的两个不同实例)本身必须是“可比较的”,比较的标准由对象所在的类来定义,这种可比较的能力是对象本身固有的,因此不需要第三方参与就可以完成比较。要使得两个对象本身是可比较的,那么对象所在的类必须实现Comparable接口才可以。compareTo()方法只要一个参数,因为这里只有“你”“我”的关系,没有第三方。
比如,两个人要比较身高,分辨高矮是人类固有的能力,两个人只要站到一起就能分出谁高谁矮。

2. Comparator:“比较器”
使用这种策略来比较时,如何进行比较和两个对象本身无关,而是由第三者(即比较器)来完成的。第三方比较器需要另外专门设计:只要实现Comparator接口,任何一个类(对象)都可能成为一个“比较器”,但比较器并不是比较自己的实例,而是比较其它类的两个不同对象,比较器在这里充当“仲裁者”的角色,这也就是为什么compare()方法需要两个参数。
比如,两个人要比较谁智商更高,靠他们自身无法进行,这时要借助一个比较器(比如,智商测试题)。

注: Comparable和Comparator这两个接口和集合接口(Collection)本身无关,但通常和集合内的元素有关,因为集合的排序要用到这两个排序接口中的方法(二选其一)。一个类的多个实例要想实现排序,必须实现Comparable,或者提供相应的Comparator才能使用Collections.sort()进行排序。

这里我们需要专门说明一下:java.util.Collections,是不属于java的集合框架的,它是一个集合的工具类它包含专门操作集合(Collection)的静态方法,如排序、拷贝、匹配查找等等,比如我们常用它的排序方法:Collections.sort(List), Collections.sort(List, Comparator)
二、代码示例

1. 假如你维护着一个简单的员工数据库,每个员工是一个Employee类的实例。

Employee类可定义为:

  1. public class Employee {   
  2.     private String num;  
  3.     private String name;  
  4.     private int age;  
  5.     private int salary;   
  6.     public Employee(String num, String name) {  
  7.         this.num = num;  
  8.         this.name = name;  
  9.     }     
  10.     public void setName(String newNum) {  
  11.         num = newNum;  
  12.     }  
  13.   
  14.     public void setAge(int newAge) {  
  15.         age = newAge;  
  16.     }  
  17.     public void setSalary(int newSalary) {  
  18.         salary = newSalary;  
  19.     }  
  20.     public String getNum() {  
  21.         return num;  
  22.     }  
  23.     public String getName() {  
  24.         return name;  
  25.     }  
  26.     public int getAge() {  
  27.         return age;  
  28.     }  
  29.     public int getSalary() {  
  30.         return salary;  
  31.     }  
  32.     public String toString() {  
  33.         StringBuffer sb = new StringBuffer();  
  34.         sb.append("Employee Information:");  
  35.         sb.append("\n");  
  36.         sb.append("Number:");  
  37.         sb.append(getNum());  
  38.         sb.append("\n");  
  39.         sb.append("Name:");  
  40.         sb.append(getName());  
  41.         sb.append("\n");  
  42.         sb.append("Age:");  
  43.         sb.append(getAge());  
  44.         sb.append("\n");  
  45.         sb.append("Salary:");  
  46.         sb.append(getSalary());  
  47.         sb.append("\n");  
  48.         return sb.toString();  
  49.     }  
  50. }  
EmployeeDatabase类创建Employee类的实例,并把它们存入集合:
  1. import java.util.*;  
  2.   
  3. public class EmployeeDatabase {  
  4.       
  5.     public static void main(String[] args) {  
  6.           
  7.         List<Employee> allEmployees = new ArrayList<Employee>();  
  8.           
  9.         Employee employee1 = new Employee("AAA""Barack Omaba");  
  10.         employee1.setAge(50);  
  11.         employee1.setSalary(9999);  
  12.         allEmployees.add(employee1);  
  13.           
  14.         Employee employee2 = new Employee("BBB""George Bush");  
  15.         employee2.setAge(60);  
  16.         employee2.setSalary(5999);  
  17.         allEmployees.add(employee2);  
  18.           
  19.         System.out.println(allEmployees);  
  20.   
  21.     }  
  22.   
  23. }  

2. 现在,你需要检索所有员工,并让他们按一定顺序显示(比如按年龄递增)这时需要用到Collections.sort()方法

Collections.sort()有两种策略:一种是让集合中元素所属类本身实现Comparable接口,另一种是使用用户另外提供的比较器(即Comparator)。

2.1 使用第一种策略时,必须修改元素类的定义让它实现Comparable接口,因此,你必须把Employee类修改为:
  1. public class Employee implements Comparable<Employee> {  
  2.       
  3.     public int compareTo(Employee another) {  
  4.         return getAge() - another.getAge();  
  5.     }  
  6.       
  7.     // 其余部分不变  
  8.   
  9. }  
说明一下,因为compareTo()方法约定:本对象大于另一个对象时,返回大于0的整数,小于时返回小于0的整数,等于时返回0。所以,可以直接返回两者年龄的差,来实现按年龄比较。这样就可以在main()方法中使用Collections.sort(allEmployees);来对员工按年龄排序了。
但是,这种排序是非常不灵活的:

第一,需要修改集合元素类Employee,而很多情况下,我们没有办法修改公共的类。
第二,没有办法实现多种方式排序,如按编号,按姓名,按薪水等等。
2.2 这时需要使用另一种策略,创建一个比较器类,其需要实现Comparator接口。Comparator使用其compare()方法返回的整数来比较两个对象,规则和compareTo()一样。
如同样实现年龄比较,使用Comparator时,无需修改Employee类,可以在排序的时候定义相应的比较器。使用Collections.sort()方法的另一个版本:
  1. Collections.sort(allEmployees, new Comparator<Employee>() {  
  2.     public int compare(Employee one, Employee another) {  
  3.         return one.getAge() - another.getAge();  
  4.     }  
  5. });  
这里代码使用了匿名内部类,实际上相当于先定义一个比较器类,如:
  1. class EmployeeComparator implements Comparator<Employee> {  
  2.       
  3.     public int compare(Employee one, Employee another) {  
  4.         return one.getAge() - another.getAge();  
  5.     }  
  6.       
  7. }  
再使用:
  1. Collections.sort(allEmployees, new EmployeeComparator());  
可以看到,比较器完全独立于元素类Employee,因此可以非常方便地修改排序规则。
你还可以定义一系列比较器,供排序时选择使用,如:
  1. // 按薪水升序  
  2. class EmployeeSalaryAscendingComparator implements Comparator<Employee> {  
  3.       
  4.     public int compare(Employee one, Employee another) {  
  5.         return one.getSalary() - another.getSalary();  
  6.     }  
  7.       
  8. }  
  9.   
  10. // 按薪水降序  
  11. class EmployeeSalaryDescendingComparator implements Comparator<Employee> {  
  12.       
  13.     public int compare(Employee one, Employee another) {  
  14.         return another.getSalary() - one.getSalary();  
  15.     }  
  16.       
  17. }  
相应的使用方法如:
  1. Collections.sort(allEmployees, new EmployeeSalaryAscendingComparator());  
  2. Collections.sort(allEmployees, new EmployeeSalaryDescendingComparator());  
等等....

使用Comparator时,元素类无需实现Comparable,因此我们保持最初版本的Employee,但实际应用中,可以用Comparable的compareTo()方法来定义默认排序方式,用Comparator定义其他排序方式。

三、总结-Camparable接口和Comparator接口的比较

1. Camparable的使用方式是:在欲比较的类内部定义实现compareTo()方法,然后再使用Collections. sort()来实现排序,而Comparator是在欲比较的类外部实现的排序。所以,如想实现排序,就需要在在类内实现Comparable接口的方法compareTo() 或类外定义实现Comparator接口的方法compare()。
Comparable是一个对象本身就已经支持自比较所需要实现的接口(如String ,Integer自己就可以完成比较大小操作),而Comparator是一个专用的比较器,当这个对象不支持自比较或者自比较函数不能满足你的要求时,你可以写一个比较器来完成两个对象之间大小的比较。
2.一个类实现了Camparable接口则表明这个类的对象之间是可以相互比较的,这个类对象组成的集合就可以直接使用sort()方法排序。一般我们写的bean都要都要实现这一接口,这也是标准javabean的规范。
3.Comparator可以看成一种算法的实现,将算法和数据分离,Comparator也可以在下面两种场景下使用:
3.1 类的设计师没有考虑到比较问题而没有实现Camparable接口,我们可以通过Comparator来实现排序而不必改变类本身。比如,你使用了一个第三方的类,但这个第三方类么有实现Camparable接口,而你又不能改它的代码,另外,类一旦写好后是不允许修改的,但 可以拓展,这时候只能使用Comparator来实现排序。
3.2 可以使用多种排序标准,比如升序、降序等。
比如,实现Comparable只能定义一种比较方法即compareTo(),但是有时候会对一个集合进行不同的排序方法,此时就可以提供别各种各样的Comparator来对集合排序,而对于要排序的元素不需要更改,所以我觉得Comparator提供了更多的灵活性。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值