Java 内接口排序和外接口排序

Java之Comparable接口(内部排序接口)与Comparator接口(外部排序接口)

Comparable接口

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

Comparable 定义
Comparable 接口仅仅只包括一个函数,它的定义如下:

public interface Comparable<T> {   
 public int compareTo(T o); 
 }

关于返回值:
可以看出compareTo方法返回一个int值,该值有三种返回值:

  1. 返回负数:表示当前对象小于比较对象
  2. 返回0:表示当前对象等于目标对象
  3. 返回正数:表示当前对象大于目标对象

Comparator接口

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

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

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

Comparator 定义
Comparator 接口仅仅只包括两个个函数,它的定义如下:

package java.util;
public interface Comparator<T> {
      int compare(T o1, T o2);
      boolean equals(Object obj);
       }

int compare(T o1, T o2) 是“比较o1和o2的大小”。

  1. 返回“负数”,意味着“o1比o2小”;
  2. 返回“零”,意味着“o1等于o2”;
  3. 返回“正数”,意味着“o1大于o2”。

Comparator 和 Comparable 比较:

所谓内外排序都是相对于类的。Comparable是排序接口;若一个类实现了Comparable接口,就意味着“该类支持排序”。 而Comparator是比较器;若需要控制某个类的次序,可以建立一个“该类的比较器”来进行排序。

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

代码示例

1.我们创建一个CSVData类,此类是用来保存学生信息,信息来源为a.csv文件

package 排序接口;

import java.util.Comparator;

public class CsvData implements Comparable<CsvData>{

    //生成表格的变量及其Getter、Setter
    private String number;
    private String name;
    private String math;
    private String chinese;
    private String chemistry;
    private String english;
    private String Geography;
    private String history;
    private String physics;
    private String sum;
    private String average;

    public void setNumber(String number) {
        this.number = number;
    }

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

    public void setMath(String math) {
        this.math = math;
    }

    public void setChinese(String chinese) {
        this.chinese = chinese;
    }

    public void setChemistry(String chemistry) {
        this.chemistry = chemistry;
    }

    public void setEnglish(String english) {
        this.english = english;
    }

    public void setGeography(String geography) {
        Geography = geography;
    }

    public void setHistory(String history) {
        this.history = history;
    }

    public void setPhysics(String physics) {
        this.physics = physics;
    }

    public void setSum(String sum) {
        this.sum = sum;
    }

    public void setAverage(String average) {
        this.average = average;
    }

    public String getNumber() {
        return number;
    }

    public String getName() {
        return name;
    }

    public String getMath() {
        return math;
    }

    public String getChinese() {
        return chinese;
    }

    public String getChemistry() {
        return chemistry;
    }

    public String getEnglish() {
        return english;
    }

    public String getGeography() {
        return Geography;
    }

    public String getHistory() {
        return history;
    }

    public String getPhysics() {
        return physics;
    }

    public String getSum() {
        return sum;
    }

    public String getAverage() {
        return average;
    }

    public String getmessage(){
        return(number + "\t" + name + "\t" + math + "\t" + chinese + "\t" + chemistry + "\t" + english
                + "\t" + Geography + "\t" + history + "\t" + physics + "\t" + sum + "\t" + average);
    }

    public int compareTo(CsvData s) {
        //升序   Comparable
        int num = Integer.parseInt(this.sum)-Integer.parseInt(s.sum);
        //如果分数相同就比较名字
        return num==0 ? this.name.compareTo(s.name): num;
    }
}

测试类:

package 排序接口;

import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;

public class test {
    public static void main(String[] args) {

        System.out.println("********************排序前*********************");
        System.out.println("学号  姓名  数学 语文 化学 英语 地理 历史 物理 总分 平均分");
        LinkedList<CsvData> listRead;
        //读入数据
        listRead = CSVio.readCSV("E://a.csv");
        //取前20个数据
        List<CsvData> listRead1 = listRead.subList(0,20);
        for (int i = 0 ; i < listRead1.size(); i++ )
        System.out.println(listRead1.get(i).getmessage());

        System.out.println("************Comparable list排序(升序,可以重复的)*****************");
        System.out.println("学号  姓名  数学 语文 化学 英语 地理 历史 物理 总分 平均分");
        Collections.sort(listRead1);//Comparable list 排序
        for(CsvData s:listRead1){
            System.out.println(s.getmessage());
        }

        Collections.sort(listRead1, new Comparator<CsvData>() {//内部类  Comparator
            @Override
            public int compare(CsvData o1, CsvData o2) {//降序
                return Integer.parseInt(o2.getSum()) - Integer.parseInt(o1.getSum());
            }
        });

        System.out.println("*************Comparator list 排序(降序,可以重复的)*****************");
        System.out.println("学号  姓名  数学 语文 化学 英语 地理 历史 物理 总分 平均分");
        for(CsvData s:listRead1){
            System.out.println(s.getmessage());
        }
    }
}

这时需要用到Collections.sort()方法

现在,你需要检索所有信息,并让他们按一定顺序显示(比如按成绩递增)Collections.sort()有两种策略:一种是让集合中元素所属类本身实现Comparable接口,另一种是使用用户另外提供的比较器(即Comparator)。

但实际应用中,可以用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也可以在下面两种场景下使用:
1) 类的设计师没有考虑到比较问题而没有实现Camparable接口,我们可以通过Comparator来实现排序而不必改变类本身。比如,你使用了一个第三方的类,但这个第三方类么有实现Camparable接口,而你又不能改它的代码,另外,类一旦写好后是不允许修改的,但 可以拓展,这时候只能使用Comparator来实现排序。

2) 可以使用多种排序标准,比如升序、降序等。
比如,实现Comparable只能定义一种比较方法即compareTo(),但是有时候会对一个集合进行不同的排序方法,此时就可以提供别各种各样的Comparator来对集合排序,而对于要排序的元素不需要更改,所以我觉得Comparator提供了更多的灵活性。

导入数据的类,目标数据文件为csv

package 排序接口;

import java.io.*;
import java.util.LinkedList;
import java.util.List;

public class CSVio {
    /**
     * 读取 CSV 文件
     *
     * @return
     */
    public static LinkedList<CsvData> readCSV(String path) {
        LinkedList<CsvData> list = new LinkedList<>();
        BufferedReader reader = null;
        try {
            FileInputStream fis = new FileInputStream(path);
            InputStreamReader isr = new InputStreamReader(fis, "GBK");
            reader = new BufferedReader(isr);
            String line;
            while ((line = reader.readLine()) != null) {
                String[] rows = line.split(",");
                CsvData info = new CsvData();
                info.setNumber(rows.length > 0 ? rows[0] : null);
                info.setName(rows.length > 1 ? rows[1] : null);
                info.setMath(rows.length > 2 ? rows[2] : null);
                info.setChinese(rows.length > 3 ? rows[3] : null);
                info.setChemistry(rows.length > 4 ? rows[4] : null);
                info.setEnglish(rows.length > 5 ? rows[5] : null);
                info.setGeography(rows.length > 6 ? rows[6] : null);
                info.setHistory(rows.length > 7 ? rows[7] : null);
                info.setPhysics(rows.length > 8 ? rows[8] : null);
                info.setSum(rows.length > 9 ? rows[9] : null);
                info.setAverage(rows.length > 10 ? rows[10] : null);
                list.add(info);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        if (!list.isEmpty()) {
            // 移除 CSV 首行标题
            list.remove(0);
        }
        return list;
    }

    /**
     * 写入 CSV 文件
     *
     * @return
     */
    public static void writeCsv(List<CsvData> dataList, String filePath) {
        CsvData header = new CsvData();
        //设置表头
        dataList.add(0, header);
        try {
            FileOutputStream fos = new FileOutputStream(new File(filePath));
            OutputStreamWriter osw = new OutputStreamWriter(fos, "GBK");
            BufferedWriter bw = new BufferedWriter(osw);
            for (CsvData data : dataList) {
                String line = data.getNumber() + ","
                        + data.getName() + ","
                        + data.getMath() + ","
                        + data.getChinese() + ","
                        + data.getEnglish();
                //等等
                bw.write(line + "\t\n");
            }
            bw.close();
            osw.close();
            fos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

学习引用参考:

https://blog.csdn.net/zolalad/article/details/30060499

https://www.cnblogs.com/cikai/p/13632000.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值