Collections.sort方法对list排序的两种方式:Comparable接口和Comparator接口

参考了原文:https://blog.csdn.net/qq_23179075/article/details/78753136

以及:https://www.cnblogs.com/Kevin-mao/p/5912775.html

Java中实现对象的比较:Comparable接口和Comparator接口

在实际应用中,我们往往有需要比较两个自定义对象大小的地方。而这些自定义对象的比较,就不像简单的整型数据那么简单,它们往往包含有许多的属性,我们一般都是根据这些属性对自定义对象进行比较的。

所以Java中要比较对象的大小或者要对对象的集合进行排序,需要通过比较这些对象的某些属性的大小来确定它们之间的大小关系。

一般,Java中通过接口实现两个对象的比较,比较常用就是Comparable接口和Comparator接口。

首先类要实现接口,并且使用泛型规定要进行比较的对象所属的类,然后类实现了接口后,还需要实现接口定义的比较方法(compareTo方法或者compare方法),在这些方法中传入需要比较大小的另一个对象,通过选定的成员变量与之比较,如果大于则返回1,小于返回-1,相等返回0。

1. 接口Comparable

此接口强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序,类的 compareTo 方法被称为它的自然比较方法。

实现此接口的对象列表(和数组)可以通过 Collections.sort(和 Arrays.sort )进行自动排序。实现此接口的对象可以用作有序映射表中的键或有序集合中的元素,无需指定比较器

Collections.sort方法对list排序的两种方式:Comparable接口和Comparator接口_第1张图片
很多类都实现了这个接口,如String,Double等。
这个接口只有一个方法:
在这里插入图片描述
下面看看类中的compareTo()方法:
Collections.sort方法对list排序的两种方式:Comparable接口和Comparator接口_第2张图片

在这里插入图片描述

public int compareTo(String anotherString)
返回:

  • 如果参数字符串等于此字符串,则返回值 0;如果此字符串按字典顺序小于字符串参数,则返回一个小于 0的值;如果此字符串按字典顺序大于字符串参数,则返回一个大于 0 的值。

String类中是如何实现compareTo方法的:

public int compareTo(String anotherString) {
        int len1 = value.length;
        int len2 = anotherString.value.length;
        int lim = Math.min(len1, len2);
        char v1[] = value;
        char v2[] = anotherString.value;
 
        int k = 0;
        while (k < lim) {
            char c1 = v1[k];
            char c2 = v2[k];
            if (c1 != c2) {
                return c1 - c2;
            }
            k++;
        }
        return len1 - len2;
    }

由JDK源码可以看出:

          首先取出两个字符串的长度,比较较小的长度内,两者是否相等。

          若不相等,则直接返回该位置字符的UNICODE码相减后的值。

          若各位置都相等,则将两个字符串长度的差值返回。

例如Date类,Integer类都与此类似。

在日常开发中,很多时候都需要对一些数据进行排序的操作。然而那些数据一般都是放在一个集合中如:Map ,Set ,List 等集合中。他们都提共了一个排序方法 sort(),要对数据排序直接使用这个方法就行,但是要保证集合中的对象是可比较的。

怎么让一个对象是可比较的,那就需要该对象实现 Comparable 接口啦。然后重写里面的 compareTo() 方法。我们可以看到Java中很多类都是实现类这个接口的 如:Integer,Long 等等。。。

要实现对目标对象(如student)的排序,就必须在Student类中实现Comparable接口!!!

实例一:
假设我们有一个学生类,默认需要按学生的年龄字段 age 进行排序 代码如下:

public class Student implements Comparable {
    private int id;
    private int age;
    private String name;

    public Student(int id, int age, String name) {
        this.id = id;
        this.age = age;
        this.name = name;
    }
    @Override
    public int compareTo(Student o) {
        //降序
        //return o.age - this.age;
        //升序
        return this.age - o.age;        
    }
    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}


测试代码:

public static void main(String args[]){
        List list = new ArrayList<>();
        list.add(new Student(1,25,"关羽"));
        list.add(new Student(2,21,"张飞"));
        list.add(new Student(3,18,"刘备"));
        list.add(new Student(4,32,"袁绍"));
        list.add(new Student(5,36,"赵云"));
        list.add(new Student(6,16,"曹操"));
        System.out.println("排序前:");
        for (Student student : list) {
            System.out.println(student.toString());
        }
        //使用默认排序
        Collections.sort(list);//按照重写的compareTo()方法中的比较规则进行排序,若没有进行重写,则默认排序
        System.out.println("默认排序后:");
        for (Student student : list) {
            System.out.println(student.toString());
        }

输出:

排序前:
Student{id=1, age=25, name='关羽'}
Student{id=2, age=21, name='张飞'}
Student{id=3, age=18, name='刘备'}
Student{id=4, age=32, name='袁绍'}
Student{id=5, age=36, name='赵云'}
Student{id=6, age=16, name='曹操'}
默认排序后:
Student{id=6, age=16, name='曹操'}
Student{id=3, age=18, name='刘备'}
Student{id=2, age=21, name='张飞'}
Student{id=1, age=25, name='关羽'}
Student{id=4, age=32, name='袁绍'}
Student{id=5, age=36, name='赵云'}
--------------------- 
作者:宇智波为什么带土 
来源:CSDN 
原文:https://blog.csdn.net/qq_23179075/article/details/78753136 
版权声明:本文为博主原创文章,转载请附上博文链接!


这个时候需求又来了,默认是用 age 排序,但是有的时候需要用 id 来排序怎么办? 这个时候比较器 :Comparator 就排上用场了。

2. 接口Comparator(比较器的使用)

Collections.sort方法对list排序的两种方式:Comparable接口和Comparator接口_第3张图片

强行对某个对象 collection 进行整体排序 的比较函数。

可以将 Comparator 传递给 sort 方法(如 Collections.sort 或 Arrays.sort),从而允许在排序顺序上实现精确控制。
还可以使用 Comparator 来控制某些数据结构(如有序 set或有序映射)的顺序,或者为那些没有自然顺序的对象 collection 提供排序。

这个接口只有两个方法:
Collections.sort方法对list排序的两种方式:Comparable接口和Comparator接口_第4张图片

Comparator 的使用有两种方式:

Collections.sort(list,Comparator);
list.sort(Comparator);

其实主要是看 Comparator 接口的实现,重写里面的 compare 方法。代码如下:

//自定义排序1
Collections.sort(list, new Comparator() {
    @Override
    public int compare(Student o1, Student o2) {
        return o1.getId() - o2.getId();
    }
});

compare(Student o1, Student o2) 方法的返回值跟 Comparable<> 接口中的 compareTo(Student o) 方法 返回值意思相同。另一种写法如下:

//自定义排序2
list.sort(new Comparator() {
    @Override
    public int compare(Student o1, Student o2) {
        return o1.getId() - o2.getId();
    }
});

输出:

排序前:
Student{id=1, age=25, name='关羽'}
Student{id=2, age=21, name='张飞'}
Student{id=3, age=18, name='刘备'}
Student{id=4, age=32, name='袁绍'}
Student{id=5, age=36, name='赵云'}
Student{id=6, age=16, name='曹操'}
自定义排序后:
Student{id=1, age=25, name='关羽'}
Student{id=2, age=21, name='张飞'}
Student{id=3, age=18, name='刘备'}
Student{id=4, age=32, name='袁绍'}
Student{id=5, age=36, name='赵云'}
Student{id=6, age=16, name='曹操'}

下面看第二个例子:
实例二:

package com.mxl.algorithlm;

import java.util.Date;
/**
 * 因为要实现对ConsumInfo对象的排序,所以在ConsunInfo类中要实现Comparable接口,也就是要实现compareTo()方法
 * 具体的比较参照:依次按照price、uid进行倒序排序
 * @author breeze
 *
 */
public class ConsumInfo implements Comparable {
    private int uid;
    private String name;
    private double price;
    private Date datetime;
    
    public ConsumInfo() {
        // TODO Auto-generated constructor stub
    }
    
    public ConsumInfo(int uid,String name,double price,Date datetime){
        this.uid = uid;
        this.name = name;
        this.price = price;
        this.datetime = datetime;
                
    }
    
    public int getUid() {
        return uid;
    }

    public void setUid(int uid) {
        this.uid = uid;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public Date getDatetime() {
        return datetime;
    }

    public void setDatetime(Date datetime) {
        this.datetime = datetime;
    }
    

    @Override
    public String toString() {
        return "ConsumInfo [uid=" + uid + ", name=" + name + ", price=" + price
                + ", datetime=" + datetime + "]";
    }
    /**
     * 这里比较的是什么, Collections.sort方法实现的就是按照此比较的东西排列
     * 顺序(从小到大):
     * if(price < o.price){
            return -1;
        }
        if(price > o.price){
            return 1;
        }
     * 倒序(从大到小):
     * if(price < o.price){
            return 1;
        }
        if(price > o.price){
            return -1;
        }
     * 
     */
    @Override
    public int compareTo(ConsumInfo o) {
        //首先比较price,如果price相同,则比较uid
        if(price < o.price){
            return -1;
        }
        if(price > o.price){
            return 1;
        }
        
        if(price == o.price){
            if(uid < o.uid){
                return -1;
            }
            if(uid > o.uid){
                return 1;
            }
        }
        return 0;
    }
    
    
}

//测试类

package com.mxl.algorithlm;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;

public class ConsumInfoTest {
    
    public static void main(String[] args) {
        
        ConsumInfo consumInfo1 = new ConsumInfo(100, "consumInfo1", 400.0,new Date());
        ConsumInfo consumInfo2 = new ConsumInfo(200, "consumInfo1", 200.0,new Date());
        ConsumInfo consumInfo3 = new ConsumInfo(300, "consumInfo1", 100.0,new Date());
        ConsumInfo consumInfo4 = new ConsumInfo(400, "consumInfo1", 700.0,new Date());
        ConsumInfo consumInfo5 = new ConsumInfo(500, "consumInfo1", 800.0,new Date());
        ConsumInfo consumInfo6 = new ConsumInfo(600, "consumInfo1", 300.0,new Date());
        ConsumInfo consumInfo7 = new ConsumInfo(700, "consumInfo1", 900.0,new Date());
        ConsumInfo consumInfo8 = new ConsumInfo(800, "consumInfo1", 400.0,new Date());
        
        List list = new ArrayList();
        list.add(consumInfo1);
        list.add(consumInfo2);
        list.add(consumInfo3);
        list.add(consumInfo4);
        list.add(consumInfo5);
        list.add(consumInfo6);
        list.add(consumInfo7);
        list.add(consumInfo8);
        System.out.println("排序前:");
        //排序前
        for(ConsumInfo consumInfo : list ){
            System.out.println(consumInfo);
        }
        
        Collections.sort(list);//排序,按照compareTo()中定义的比较规则进行排序
        System.out.println("排序后:");
        //排序后
        for(ConsumInfo consumInfo :list){
            System.out.println(consumInfo);
        }
    }
}

与Comparable接口不同的是:

①、Comparator位于包java.util下,而Comparable位于包java.lang下。

②、Comparable接口将比较代码嵌入需要进行比较的类的自身代码中,而Comparator接口在一个独立的类中实现比较。

③、如果前期类的设计没有考虑到类的Compare问题而没有实现Comparable接口,后期可以通过Comparator接口来实现比较算法进行排序,并且为了使用不同的排序标准做准备,比如:升序、降序。

④、Comparable接口强制进行自然排序,而Comparator接口不强制进行自然排序,可以指定排序顺序。

实例三:

package test;

import java.util.Comparator;
/**
 * 具体的比较类(比较器),实现Comparator接口
 *
 */
public class ComparatorConsunInfo implements Comparator {
  
    @Override
    public int compare(ConsumInfo o1, ConsumInfo o2) {
         //首先比较price,如果price相同,则比较uid
        if(o1.getPrice() > o2.getPrice()){
            return 1;
        }
        
        if(o1.getPrice() < o2.getPrice()){
            return -1;
        }
        
        if(o1.getPrice() == o2.getPrice()){
            if(o1.getUid() > o2.getUid()){
                return 1;
            }
            if(o1.getUid() < o2.getUid()){
                return -1;
            }
        }
        return 0;
    }

}


/**
 * 需要进行比较的类
 *
 */
public class ConsumInfo{
    private int uid;
    private String name;
    private double price;
    private Date datetime;
    
    public ConsumInfo() {
        // TODO Auto-generated constructor stub
    }
    
    public ConsumInfo(int uid,String name,double price,Date datetime){
        this.uid = uid;
        this.name = name;
        this.price = price;
        this.datetime = datetime;
                
    }
    
    public int getUid() {
        return uid;
    }

    public void setUid(int uid) {
        this.uid = uid;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public Date getDatetime() {
        return datetime;
    }

    public void setDatetime(Date datetime) {
        this.datetime = datetime;
    }

    @Override
    public String toString() {
        return "ConsumInfo [uid=" + uid + ", name=" + name + ", price=" + price
                + ", datetime=" + datetime + "]";
    }
    
}


//测试类
public class ConsumInfoTest {
    
    public static void main(String[] args) {
        
        ConsumInfo consumInfo1 = new ConsumInfo(100, "consumInfo1", 400.0,new Date());
        ConsumInfo consumInfo2 = new ConsumInfo(200, "consumInfo1", 200.0,new Date());
        ConsumInfo consumInfo3 = new ConsumInfo(300, "consumInfo1", 100.0,new Date());
        ConsumInfo consumInfo4 = new ConsumInfo(400, "consumInfo1", 700.0,new Date());
        ConsumInfo consumInfo5 = new ConsumInfo(500, "consumInfo1", 800.0,new Date());
        ConsumInfo consumInfo6 = new ConsumInfo(600, "consumInfo1", 300.0,new Date());
        ConsumInfo consumInfo7 = new ConsumInfo(700, "consumInfo1", 900.0,new Date());
        ConsumInfo consumInfo8 = new ConsumInfo(800, "consumInfo1", 400.0,new Date());
        
        List list = new ArrayList();
        list.add(consumInfo1);
        list.add(consumInfo2);
        list.add(consumInfo3);
        list.add(consumInfo4);
        list.add(consumInfo5);
        list.add(consumInfo6);
        list.add(consumInfo7);
        list.add(consumInfo8);
        
        System.out.println("排序前:");
        //排序前
        for(ConsumInfo consumInfo : list ){
            System.out.println(consumInfo);
        }
        ComparatorConsunInfo comparatorConsunInfo = new ComparatorConsunInfo();//定义一个比较器
        Collections.sort(list,comparatorConsunInfo);//排序
        System.out.println("排序后:");
        //排序后
        for(ConsumInfo consumInfo :list){
            System.out.println(consumInfo);
        }
    }
}

精华部分:

ComparatorConsunInfo comparatorConsunInfo = new ComparatorConsunInfo();//定义一个比较器
Collections.sort(list,comparatorConsunInfo);//排序

参考了原文:https://blog.csdn.net/qq_23179075/article/details/78753136

以及:https://www.cnblogs.com/Kevin-mao/p/5912775.html
版权声明:本文为博主原创文章,转载请附上博文链接!

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