Java中compareable和comparator的区别

一、对比简介

实现compareable接口与Comparator接口的类,都是为了对象实例数组排序的方便,因为可以直接调用
java.util.Arrays.sort(对象数组名称),可以自定义排序规则。排序实现的原理都是基于红黑二叉树原理实现的。

  • Comparable是排序接口。若一个类实现了Comparable接口,就意味着该类支持排序。实现了Comparable接口的类的对象的列表或数组可以通过Collections.sort或Arrays.sort进行自动排序。
  • Comparator是比较接口,我们如果需要控制某个类的次序,而该类本身不支持排序(即没有实现Comparable接口),那么我们就可以建立一个“该类的比较器”来进行排序,这个“比较器”只需要实现Comparator接口即可。也就是说,我们可以通过实现Comparator来新建一个比较器,然后通过这个比较器对类进行排序。

不同之处:
1 排序规则实现的方法不同

  • Comparable接口的方法:compareTo(Object o)

  • Comparator接口的方法:compare(T o1, To2)

2 类设计前后不同

  • Comparable接口用于在类的设计中使用;设计初期,就实现这个借口,指定排序方式。

  • Comparator接口用于类设计已经完成,还想排序(Arrays)。

二、Comparable接口的实例操作

N多的类中都有该compareTo方法,根本原因是因为它们都实现了接口comparable接口,并且实现了接口中的compareTo方法。

实现Compareable的jdk源码类
在这里插入图片描述

扫描二维码关注公众号,回复: 8601639 查看本文章

Student类创建时实现Comparable接口,覆写compareTo()方法,

成绩按从高到低排序,成绩相等按年龄从小到大排序。

package ch11.lei.ji;
/*实现Comparator接口的类可以方便的排序,
 * 覆写compareTo接口
 * java.util.Arrays.sort(对象类数组),*/
class Student implements Comparable<Student> {    // 指定类型为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" + this.age + "\t\t" + this.score ;
    }
    public int compareTo(Student stu){    // 覆写compareTo()方法,实现排序规则的应用
        if(this.score>stu.score){
            return -1 ;
        }else if(this.score<stu.score){
            return 1 ;
        }else{
            if(this.age>stu.age){
                return 1 ;
            }else if(this.age<stu.age){
                return -1 ;
            }else{
                return 0 ;
            }
        }    
    }
};
public class Comparable01{
    public static void main(String args[]){
        Student stu[] = {new Student("张三",20,90.0f),
            new Student("李四",22,90.0f),new Student("王五",20,99.0f),
            new Student("赵六",20,70.0f),new Student("孙七",22,100.0f)} ;
        java.util.Arrays.sort(stu) ;    // 进行排序操作
        for(int i=0;i<stu.length;i++){    // 循环输出数组中的内容
            System.out.println(stu[i]) ;
        }
    }
};

三、Comparator接口实例操作

Student01类原先没有比较器,类完成后构建一个比较器StudentComparator类

按年龄从大到小排序。

package ch11.lei.ji;
import java.util.* ;
 class Student01{    // 指定类型为Student
    private String name ;
    private int age ;
    public Student01(String name,int age){
        this.name = name ;
        this.age = age ;
    }
    public boolean equals(Object obj){    // 覆写equals方法
        if(this==obj){
            return true ;
        }
        if(!(obj instanceof Student)){
            return false ;
        }
        Student01 stu = (Student01) obj ;
        if(stu.name.equals(this.name)&&stu.age==this.age){
            return true ;
        }else{
            return false ;
        }
    }
    public void setName(String name){
        this.name = name ;
    }
    public void setAge(int age){
        this.age = age ;
    }
    public String getName(){
        return this.name ;
    }
    public int getAge(){
        return this.age ;
    }
    public String toString(){
        return name + "\t\t" + this.age  ;
    }
};

class StudentComparator implements Comparator<Student01>{    // 实现比较器
    // 因为Object类中本身已经有了equals()方法
    public int compare(Student01 s1,Student01 s2){
        if(s1.equals(s2)){
            return 0 ;
        }else if(s1.getAge()<s2.getAge()){    // 按年龄比较
            return 1 ;
        }else{
            return -1 ;
        }
    }
};

public class Comparator01{
    public static void main(String args[]){
        Student01 stu[] = {new Student01("张三",20),
            new Student01("李四",22),new Student01("王五",20),
            new Student01("赵六",20),new Student01("孙七",22)} ;
        java.util.Arrays.sort(stu,new StudentComparator()) ;    // 进行排序操作
        for(int i=0;i<stu.length;i++){    // 循环输出数组中的内容
            System.out.println(stu[i]) ;
        }
    }
};

注意: 1、若一个类要实现Comparator接口:它一定要实现compare(T o1, T o2) 函数,但可以不实现 equals(Object obj) 函数。

2、int compare(T o1, T o2) 是“比较o1和o2的大小”。返回“负数”,意味着“o1比o2小”;返回“零”,意味着“o1等于o2”;返回“正数”,意味着“o1大于o2”。

四、当用到自定义排序器的时候

如:Collections.sort中需要传入一个自定义的排序器,使用匿名内部类的方式,传入comparator,重写方法,使用A.compareToB的方式进行排序

    static void sortByValue(Map map) {
        List<Map.Entry<String, Integer>> list = new ArrayList<Map.Entry<String, Integer>>(map.entrySet());
        Collections.sort(list, new Comparator<Map.Entry<String, Integer>>() {
            @Override
            public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
                return o1.getValue().compareTo(o2.getValue());
            }
        });
        for (Map.Entry<String, Integer> mapping : list) {
            System.out.println("键:" + mapping.getKey() + " 值:" + mapping.getValue());
        }

注意: 这里的o1.getValue().compareTo(o2.getValue())是字符串本身就实现了的比较方法
String类实现的接口
public final class String extends Object implements Serializable, Comparable<String>, CharSequence

五、Comparable和Comparator区别比较

Comparable是排序接口,若一个类实现了Comparable接口,就意味着“该类支持排序”。而Comparator是比较器,我们若需要控制某个类的次序,可以建立一个“该类的比较器”来进行排序。

Comparable相当于“内部比较器”,而Comparator相当于“外部比较器”。

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

六、拓展:集合TreeSet(自然排序与定制排序)

一、TreeSet的自然排序:

步骤:

1.让元素自身具备比较性,

2.实现Compareable接口,覆盖其CompareTo方法

例:

Class Student  implements Comparable//第一:实现Compareable接口

{

private String   name;

private int age;


 //复写构造函数初始化姓名跟年龄


Student(String name,int age)

{

   this.name = name;

   this.age = age;

}


public int compareTo(Object obj) //第二:复写CompareTo方法

{
 
   //return 0;

   if(!(objinstanceof Student))   //第三:判断对象是否是特定类的一个实例

       throw new RuntimeException("不是学生对象");

   Student s = (Student)obj;

   System.out.println(this.name+"....compareto....."+s.name);


//第四:当前对象的年龄与插入对象的年龄进行比较,当前年龄大于插入对象的年龄时,返回1,

此时将插入二叉树的右边,当等于时,返回0,进行次要条件的比较,再次调用;当小于时,返回-1;


   if(this.age>s.age)     //判断当前对象年龄是否大于传入的对象年龄

       return 1;

   if(this.age==s.age)     //如果当前年龄等于传入对象的年龄,则比较姓名是否相同

   {

       return this.name.compareTo(s.name);

   }

   return -1;

   /**/

}


public String getName()   //获取姓名

{
   return  name;
}
public int getAge()    //获取年龄
{
   return  age;
}
}
 
Class TreeSetDemo

{

public static void main(String[] args)

{

   TreeSet ts = newTreeSet();   //创建一个TreeSet的集合

   ts.add(new Student("lisi02",22));      //往集合添加元素

   ts.add(new Student("lisi007",20));

   ts.add(new Student("lisi09",19));

   ts.add(new Student("lisi08",19));


   Iterator it = ts.iterator();  //初始化迭代器,遍历集合中的所有元素

   while(it.hasNext())

   {

       Student stu = (Student)it.next();

       System.out.println(stu.getName()+"..."+stu.getAge());

   }

}

}

二、TreeSet的定制排序

1、由来:当元素自身不具备比较性时,或者具备的比较性不是所需要的。
这时就要让集合自身具备比较性,在初始化时,就有了比较方式。

2、步骤:

1)实现comparator接口

2)复写compare方法

3)在创建TreeSet集合对象时,提供一个一个Comparator对象,

例:

import java.util.Comparator;

import java.util.Set;

import java.util.TreeSet;

Class Student1{

private Integer age;

public Student1(Integer age) {

   super();

   this.age = age;

}

public Integer getAge() {

   return age;

}

public void setAge(Integer age) {

   this.age = age;

}

@Override

public String toString() {

   return age + "";
}

}

 
 

class MyComparator implements Comparator{  //第一步:实现Comparator接口


@Override

public int compare(Object o1, Object o2) {   //第二步:实现一个campare方法

//判断对象是否是特定类的一个实例


   if(o1 instanceof Student1 & o2instanceof Student1){

       Student1 s1 =(Student1)o1;

       Student1 s2 =(Student1)o2;

       if(s1.getAge() > s2.getAge()){

          return -1;

       }else if(s1.getAge() < s2.getAge()){

          return 1;

       }

   }

   return 0;

}

}

 

public Class Demo15 {


public static void main(String[] args) {

   Set<Student1> s= new TreeSet(new  MyComparator());//第三步:创建TreeSet集合对象时,提供一个一个Comparator对象,

   /**

    * 要实现定制排序,需要在创建TreeSet集合对象时,提供一个一个Comparator对象,

    * 该对象里负责集合元素的排序逻辑;

    */

   s.add(new Student1(140));

   s.add(new Student1(15));

   s.add(new Student1(11));

   s.add(new Student1(63));

   s.add(new Student1(96));

   System.out.println(s);

}


}

参考文章:
https://blog.csdn.net/wilson27/article/details/90339765
https://www.cnblogs.com/xujian2014/p/5215082.html
https://blog.csdn.net/liuchuangjin/article/details/46500283

发布了107 篇原创文章 · 获赞 14 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/belongtocode/article/details/102930203