【Java 开发语言07.2】【集合-定制排序】详解自然排序compareTo+比较器排序compare+两种定制排序的区别,用法+TreeSet,TreeMap存储定制排序的类对象

1 两种接口对应比较方法的参数含义及原理

在继承接口Comparable< E >实现方法compareTo(E o)和继承接口Comparator< E >实现方法compare(E o1, E o2)中,比较大小时,this(o2)代表当前准备添加进来需要排序的元素,o(o1)代表集合中所有已经排序完成的元素。

  • return -1 时,默认新添加的this(o2)大于o(o1),方法默认升序排序,o(o1)在前,this(o2)在后
  • return 1 时,默认新添加的this(o2)小于o(o1),方法默认升序排序,this(o2)在前,o(o1)在后。
  • return 0 时,默认this(o2)等于o(o1)
    默认都是升序,要降序可以使this(o2) < o(o1)时,return 1;this(o2)>o(o1),return -1。将排序o1(o)在前this(o2)在后,完成降序排序。

总之,只需记住,返回负数,代表 o1(o)排在前; 返回正数,代表 o2(thgis)排在前或

2 compareTo自然排序定制

2.1 用法一:可以直接用于Number对象(基本数据类型的包装类)和String对象

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

 //通过compareTo比较引用类型String类对象的大小
            System.out.println("-------------String-------------");
            String str1 = "1234y";
            System.out.println("sytudf".compareTo("syt"));//3
            System.out.println(str1.compareTo("1234y45ttyu"));//-6

            //通过compareTo比较基本数据类型的包装类大小
            //Byte字节型1字节
            //Byte只能用字符串参数装箱,且无法识别整型数据为Byte必须装箱
            System.out.println("-------------Byte-------------");
            System.out.println(new Byte("12").compareTo(new Byte("124")));//-112
            //Short短整型2字节
            //Short只能用字符串参数装箱,且无法识别整型数据为Short必须装箱
            System.out.println("-------------Short-------------");
            System.out.println(new Short("235").compareTo(new Short("345")));//-110
            //Integer整型4字节
            //Integer可以用值参数装箱,也可以用字符串参数装箱;且值参数自动识别整数数据为int作为参数自动装箱
            System.out.println("-------------Integer-------------");
            System.out.println(new Integer(45).compareTo(56));//-1
            System.out.println(new Integer("3456").compareTo(new Integer("345")));//1

            //Long长整型8字节,定义时尾部加L或l
            //Long可以用值参数装箱,也可以用字符串参数装箱,用字符串参数时不加L,l;且值参数自动识别整数l数据为Long作为参数自动装箱
            System.out.println("-------------Long-------------");
            System.out.println(new Long(7845634353543l).compareTo(7856l));//1
            System.out.println(new Long("45634").compareTo(34545L));//1;注意:用字符串参数就不用加L
            //Float单精度浮点型(小数型)4字节,定义时尾部加f或F
            //Float可以用值参数装箱,也可以用字符串参数装箱,用字符串参数时不加F,f;且值参数自动识别小数F,f数据为Float作为参数自动装箱
            System.out.println("-------------Float-------------");
            System.out.println(new Float(34.67f).compareTo(34.62F));//1
            System.out.println(new Float("35.6").compareTo(35.6f));//0
            //Double双精度浮点型(小数型)8字节,小数默认是double
            //Double可以用值参数装箱,也可以用字符串参数装箱;且值参数自动识别小数数据为Double作为参数自动装箱
            System.out.println("-------------Double-------------");
            System.out.println(new Double(3456.786).compareTo(3456.756));
            System.out.println(new Double("654.345").compareTo(645.345));

            //Character字符型,2字节。ASCII码中,1个英文字符占用1个字节,1个汉字字符占用2个字节的空间
            //Character可以用值参数装箱,不可以用字符串参数装箱;且值参数自动识别'一个字符'数据为Chacter作为参数自动装箱
            System.out.println("-------------Character-------------");
            System.out.println(new Character('y').compareTo(new Character('y')));//0
            System.out.println(new Character('8').compareTo('9'));//-1
            System.out.println(new Character('1').compareTo('A'));//-16
            //Boolean布尔型1字节
            //Boolean可以用值参数装箱,可以用字符串参数装箱;且值参数自动识别true或false数据为Boolean作为参数自动装箱
            System.out.println("-------------Boolean-------------");
            System.out.println(new Boolean(false).compareTo(true));//-1
            System.out.println(new Boolean("true").compareTo(new Boolean("true")));//0

在这里插入图片描述

  • Byte和Short只能用字符串参数,不能用值参数。所以比较时无法用值自动装箱,必须用字符串参数手动装箱后使用。
  • Character只能用值参数,不能用字符串参数。可以通过值参数在方法参数部分自动装箱
  • 其他5种基本数据类型包装类+String类既可以用值参数自动装箱,也可以用字符串参数手动装箱。可以通过值参数在方法参数部分自动装箱

2.2 用法二 : 重写compareTo以定制自定义类的排序规则

  • Student类,以属性id决定大小,实现自然排序
  • 继承接口Comparable实现方法 public int compareTo(Student o)
public class Student implements Comparable<Student>{
    //学生,三个属性,姓名,年龄,学号
    private String name;
    private int age;
    private int id;

    public Student( int id,String name, int age){
        this.name = name;
        this.age = age;
        this.id = id;

    }

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

    public int getAge(){
        return this.age;
    }
    public void setAge(int age){
        this.age = age;
    }

    public int getId(){
        return this.id;
    }

    //学号不会重复,所以以学号来决定大小
    @Override
    public int compareTo(Student o) {//o代表当前添加进来需要排序的元素,this代表集合中所有已经排序完成的元素
        if(this.id > o.id){
            return 1;//默认this大于o,o在前,this在后
        }else if(this.id < o.id){
            return -1;
        }else{
            return 0;
        }
        //return 0;
    }

    @Override
    public String toString() {
        //return super.toString();
        return getClass().getName()+"[id="+id+",name="+name+",age="+age+"]";
    }
}

//Student类继承接口Comparable<E>,实现方法compareTo(E o)
        Student stu1 = new Student(2026,"学生1",15);
        Student stu2 = new Student(2022,"学生2",23);
        Student stu3 = new Student(2020,"学生3",35);
 //1.自然排序的自定义类Student
         //TreeSet
        Set<Student> set1 = new TreeSet<>();
        set1.add(stu1);
        set1.add(stu2);
        set1.add(stu3);
        System.out.println(set1);


        //TreeMap
        Map<Student,Integer> map1 = new TreeMap<>();
        map1.put(stu1,23);
        map1.put(stu2,24);
        map1.put(stu3,45);
        System.out.println(map1);
  • 运行结果如下
实现自然排序自定义类的TreeSet[com.qx.javaTest.Student[id=2020,name=学生3,age=35], com.qx.javaTest.Student[id=2022,name=学生2,age=23], com.qx.javaTest.Student[id=2026,name=学生1,age=15]]
实现自然排序自定义类的TreeMap{com.qx.javaTest.Student[id=2020,name=学生3,age=35]=45, com.qx.javaTest.Student[id=2022,name=学生2,age=23]=24, com.qx.javaTest.Student[id=2026,name=学生1,age=15]=23}

3 compare比较器排序

在这里插入图片描述

3.1 用法一:在对应类中重写compare方法,集合参数new 自定义类对象

  • MyData类,以属性data1决定大小,实现比较器
  • 继承接口 Comparator<MyData>,实现方法 public int compare(MyData o1, MyData o2)等于是自己给自己写排序,其他类继承Comparator<MyData>也可以给MyData写排序方法
    Ctrl + I: 实现接口方法
    Ctrl + O: 重写父类方法
package com.qx.day10;

import java.util.Comparator;

public class MyData implements Comparator<MyData> {
    public MyData(){

    }
    public MyData(int data1,String name, int data2){

        this.data1 = data1;
        this.name = name;
        this.data2 = data2;
    }


    private String name;
    private int data1;
    private int data2;

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

    public void setData1(int data1){
        this.data1 = data1;
    }
    public int getData1(){
        return data1;
    }

    public void setData2(int data2){
        this.data2 = data2;
    }
    public int getData2(){
        return data2;
    }

    @Override
    public int compare(MyData o1, MyData o2) {//理解新添加需要排序的元素是o1,已经排好序的元素s为o2
        if(o1.data2 > o2.data2){
            return 1;//默认,o1>o2,o2在前,o1在后
        }else if(o1.data2 < o2.data2){
            return -1;默认,o1<o2,o1在前,o2在后
        }
        else{
            return 0;//相等
        }

        //添加顺序1,3,2,4.
       //return 0;//1
        //return 1;//1,3,2,4
        //return -1;//4,2,3,1
        //返回-1,默认o1<o2,o1排在o2之前
    }

    @Override
    public String toString() {
        //return super.toString();
        return getClass().getName()+"[data1="+data1+",name="+name+",data2="+data2+"]";
    }
}

		//MyData类继承接口Comparator<E>,实现方法compare(E o1, E o2)
        MyData d1 = new MyData(34,"数据1",56);
        MyData d2 = new MyData(45,"数据2",6778);
        MyData d3 = new MyData(23,"数据3",908);
  • 比较器排序的自定义类MyData,比较器类型的自定义类需要在new集合的时候提供该类对象作为参数Set<MyData> set2 = new TreeSet<>(new MyData());即可根据自定义方法自动排序
//2.比较器排序的自定义类MyData,比较器类型的自定义类需要在new集合的时候提供该类对象作为参数
        //TreeSet
        Set<MyData> set2 = new TreeSet<>(new MyData());
        set2.add(d1);
        set2.add(d2);
        set2.add(d3);
        System.out.println("实现比较器排序的自定义类的TreeSet"+set2);

        //TreeMap
        Map<MyData,Student> map2 = new TreeMap<>(new MyData());
        map2.put(d1,stu1);
        map2.put(d2,stu2);
        map2.put(d3,stu3);
        System.out.println("实现比较器排序的自定义类的TreeMap"+map2);
  • 运行结果
实现比较器排序的自定义类的TreeSet[com.qx.day10.MyData[data1=34,name=数据1,data2=56], com.qx.day10.MyData[data1=23,name=数据3,data2=908], com.qx.day10.MyData[data1=45,name=数据2,data2=6778]]
实现比较器排序的自定义类的TreeMap{com.qx.day10.MyData[data1=34,name=数据1,data2=56]=com.qx.javaTest.Student[id=2026,name=学生1,age=15], com.qx.day10.MyData[data1=23,name=数据3,data2=908]=com.qx.javaTest.Student[id=2020,name=学生3,age=35], com.qx.day10.MyData[data1=45,name=数据2,data2=6778]=com.qx.javaTest.Student[id=2022,name=学生2,age=23]}

3.2 用法二:普通类(即不在类中继承接口重写排序方法),new集合时,提供参数传入匿名类重写比较器,参数为new Comparator<该普通类名>(){重写比较方法compare}

    • Puppy类
  • 普通类,不实现接口
public class Puppy {

    private int id;
    private String name;
    
    public Puppy(int id,String name){
        this.name = name;
        this.id = id;
    }

    public int getId(){
        return this.id;
    }
    public void setId(int id){
        this.id = id;
    }

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

    @Override
    public String toString() {
        //return super.toString();
        return getClass().getName()+"[id="+id+",name="+name+"]";
    }

}

 //Puppy类,普通类
         Puppy p1 = new Puppy(8,"边牧");
         Puppy p2 = new Puppy(4,"伯恩山");
         Puppy p3 = new Puppy(3,"萨摩耶");
  • 普通类Puppy
  • 在集合new的时候参数传入匿名类重写比较器。
//普通类Puppy,在集合new的时候传入匿名类实现普通自定义类的定制排序方法
        //TreeSet
        //自然排序不能这样写,因为本身就是重写在自定义类中直接使用,不需要传参
//        Set<Puppy> set3 = new TreeSet<>(new Comparable<Puppy>(){
//            @Override
//            public int compareTo(Puppy o) {
//                //return 0;
//
//            }
//        });

        Set<Puppy> set3 = new TreeSet<Puppy>(new Comparator<Puppy>(){
            @Override
            public int compare(Puppy o1, Puppy o2) {
                //return 0;
                if(o1.getId() > o2.getId()){
                    return 1;
                }else if(o1.getId() < o2.getId()){
                    return -1;
                }else{
                    return 0;
                }
            }
        });
        set3.add(p1);
        set3.add(p2);
        set3.add(p3);
        System.out.println("普通自定义类在new TreeMap时传匿名对象重写比较器"+set3);


        //TreeMap,key和value都是自定义类的情况,

        Map<Puppy,MyData> map3 = new TreeMap<>(new Comparator<Puppy>(){
            @Override
            public int compare(Puppy o1, Puppy o2) {
                //return 0;
                if(o1.getId() > o2.getId()){
                    return -1;
                }else if(o1.getId() < o2.getId()){
                    return 1;
                }else{
                    return 0;
                }
            }
        });
        map3.put(p1,d1);
        map3.put(p2,d2);
        map3.put(p3,d3);
        System.out.println("普通自定义类在new TreeMap时传匿名对象重写比较器"+map3);
普通自定义类在new TreeMap时传匿名对象重写比较器[com.qx.javaTest.Puppy[id=3,name=萨摩耶], com.qx.javaTest.Puppy[id=4,name=伯恩山], com.qx.javaTest.Puppy[id=8,name=边牧]]
普通自定义类在new TreeMap时传匿名对象重写比较器{com.qx.javaTest.Puppy[id=8,name=边牧]=com.qx.day10.MyData[data1=34,name=数据1,data2=56], com.qx.javaTest.Puppy[id=4,name=伯恩山]=com.qx.day10.MyData[data1=45,name=数据2,data2=6778], com.qx.javaTest.Puppy[id=3,name=萨摩耶]=com.qx.day10.MyData[data1=23,name=数据3,data2=908]}

4 自然排序和比较器排序的区别总结

  • 自然排序本身可以用作基本数据类型的包装类(如Character,);比较器不可以
  • 重写比较器的类,new集合的时候需要参数提供对象,该对象包含此类的比较器(可以类自己重写比如MyData,也可以在new集合时提供参数比如Puppy);重写自然排序的类集合不用
  • 比较器参数o1表示集合中已经排序完成的所有元素,o2表示当前新添加的一个;自然排序参数o表示集合中已经排序完成的所有元素,对象自身this表示当前新添加的一个

5 自由改写理解定制排序返回值含义

  • 假设方法始终只return 1 ,表示的含义则为新添加的this(o2)始终更大,排在后。集合为按照元素的添加顺序存储
  • 假设方法只 return 0,表示所有添加进来的元素都相同,则只有集合为空时能存储一个元素。因为TreeSet和TreeMap的key都不可重复
  • 假设方法只 return -1 ,表示的含义则为新添加的this(o2)始终更小,排在前。集合为按照元素的添加顺序的逆序存储
  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值