Java 实现使用Comparable按照我们指定的规则排序

 更新时间:2022年04月01日 10:35:31   作者:再美不及姑娘你  
这篇文章主要介绍了Java 如何使用Comparable按照我们指定的规则排序,通过练习创建TreeSet集合使用无参构造方法,并按照年龄从小到大的顺序排序,若年龄相同再按照姓名的字母顺序排序展开内容,需要的朋友可以参考一下

练习:

存储学生对象并遍历,创建TreeSet集合使用无参构造方法,并按照年龄从小到大的顺序排序,若年龄相同再按照姓名的字母顺序排序

分析:

  • 1.创建学生类,成员变量name,age;无参构造,带参构造;get\set方法;
  • 2.创建测试类,添加数据并进行排序;直接排序会报错
  • 3.需要Student实现comparable接口并重写Comparable中的compareto方法来实现按照我们给定的顺序排序

Student类代码:

public class Student{
    //成员变量
    private String name;
    private int age;
    //构造方法
    public Student(){}
    public Student(String name,int age){
        this.age=age;
        this.name=name;
    }
    //get\set方法
​
    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 class StudentDemo {
    public static void main(String[] args) {
        //创建TreeSet对象
        TreeSet<Student>ts=new TreeSet<Student>();
        //创建学生对象
        Student s=new Student("张三",18);
        Student s1=new Student("张四",17);
        Student s2=new Student("张五",19);
        Student s3=new Student("张六",12);
        //添加数据
        ts.add(s);
        ts.add(s1);
        ts.add(s2);
        ts.add(s3);
        //遍历
        for (Student ss:ts){
           System.out.println(ss.getName()+ss.getAge());
        }
    }
​
}
​

第一次运行结果提示Student cannot be cast to java.lang.Comparable,这个时候我们就需要在Student类实现comparable接口重写compareto方法,并给定返回值

public class Student implements Comparable<Student>{
    //成员变量
    private String name;
    private int age;
    //构造方法
    public Student(){}
    public Student(String name,int age){
        this.age=age;
        this.name=name;
    }
    //get\set方法
​
    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;
    }
​
    @Override
    public int compareTo(Student o) {
   //      return 0;
   //      return 1;
   //      return-1;
    }
}

那么可以看到compareto方法中有三个返回值分别是0、1、-1三种情况;

  • 1.return 0:返回值是0的情况下再遍历集合只会在控制台打印出第一个元素;这是因为存入第一个元素时不需要比较直接存入集合,第二个 元素再存入是就需要跟第一个元素比较,但返回值为0,就会认为第二个元素跟第一个元素是相同的、重复的,就不存储,依此类推
  • 2.return 1:返回值是1的情况下再遍历集合会按照存储数据的顺序在控制台全部打印出来;同样的,第一个元素存入不比较,第二个元素与第一个元素比较,返回值为1;就会认为第二个元素比第一个元素大,排在第一个元素后面,以此类推
  • 3.return -1:与renturn 1的情况相反,也就是会按照存储数据顺序的倒序方式在控制台打印出来

思考:我们需要按照年龄的大小排序,这本质上不是只要返回值是一个正数就行了嘛,那我们就可以在compareto方法中这样写

public int compareTo(Student s) {
        //return 0;
        //return 1;
        int num=this.age-s.age;
        return num;
    }

其中,this是方法内部就有的,在这里this.age代表当第一个元素存储后的后续每一个元素的年龄,我们用后续存储的元素年龄减去第一个元素的年龄当结果是-1时,就将该元素排在第一个元素前面,为1时,就排在后面,为0时就代表重复不存储

但是在我们完成按照年龄进行排序后有出现一个问题:当两个元素姓名不同年龄相同时,再按照我们设定的规则就不会将年龄相同的最后一个元素存储进去,因为它们两个年龄相减为0,默认重复了。所以在年龄相同的情况下,我们还要再比较姓名,

如下:

public int compareTo(Student s) {
        //return 0;
        //return 1;
        int num=this.age-s.age;
        int num1=num==0?this.name.compareTo(s.name):num;
        return num1;
​
    }

当年龄不同时返回的还是之前num的值,当年龄相同时比较姓名是否相同不相同返回1代表可以进行存储,相同返回0代表重复。

在这里因为string 本身就实现了comparable接口,所以可以直接调用compareto方法,这样就很好的解决了问题又保证了数据的唯一性

总结:

  • 1.TreeSet集合存储自定义对象时,无参构造方法使用的是自然排序也就是按照存储元素的顺序进行排序
  • 2.自然排序也就是让元素所属的类实现Comparable接口,重写compareto(T o)方法
  • 3.重写compareto(T o)方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写

比较器排序Comparator

练习:

存储学生对象并遍历,创建TreeSet集合使用带参构造方法,并按照年龄从小到大的顺序排序,若年龄相同再按照姓名的字母顺序排序

分析:较于comparable来说,comparator无需在Student类中实现comparable接口,可以直接在创建TreeSet集合对象时使用内部类的方式进行

public class StudentDemo {
    public static void main(String[] args) {
        //创建TreeSet对象
        TreeSet<Student>ts=new TreeSet<Student>(new Comparator<Student>() {
            @Override
            public int compare(Student s1, Student s2) {
               int num =s1.getAge()-s2.getAge();
               int num1=num==0?s1.getName().compareTo(s2.getName()):num;
               return  num1;
            }
        });
        //创建学生对象
        Student s=new Student("张三",18);
        Student s1=new Student("张四",17);
        Student s2=new Student("张五",19);
        Student s3=new Student("张六",12);
        Student s4=new Student("张七",12);
        //添加数据
        ts.add(s);
        ts.add(s1);
        ts.add(s2);
        ts.add(s3);
        ts.add(s4);
        for (Student ss:ts){
            System.out.println(ss.getName()+ss.getAge());
        }
    }
​
}
​

其中需要注意的是,compare方法传递了两个参数,s1就等同于compareto中的this,但由于内部类无法直接访问Student类的私有成员变量,只能通过get方式来获取,效果等同于自然排序Comparable

感谢1楼前辈给出的指导,文中出现的错误与更正如下:

1.TreeSet集合存储自定义对象时,无参构造方法使用的是自然排序也就是按照存储元素的顺序进行排序) 正确的总结:使用TreeSet时,要么实现Comparable接口,要么指定Comparator,两者并存时优先使用Comparator。否则add方法报错cannot be cast to java.lang.Comparable

可以在TreeMap中找到源码:

/**
 * Compares two keys using the correct comparison method for this TreeMap.
 */
@SuppressWarnings("unchecked")
final int compare(Object k1, Object k2) {
    return comparator==null ? ((Comparable<? super K>)k1).compareTo((K)k2)
        : comparator.compare((K)k1, (K)k2);
}
// Student未实现Comparable接口时,初始化TreeSet时,需指定Comparator
TreeSet<Student> ts2 = new TreeSet<>(Comparator.comparingInt(Student::getAge).thenComparing(Student::getName));
ts.add(new Student("张三", 18));

到此这篇关于Java 如何使用Comparable按照我们指定的规则排序的文章就介绍到这了,更多相关Java使用Comparable指定排序内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • java dom4j解析xml用到的几个方法

    java dom4j解析xml用到的几个方法

    这篇文章主要介绍了java dom4j解析xml用到的几个方法,有需要的朋友可以参考一下
    2013-12-12
  • 浅谈Java之终止继承:Final类和Fianl方法

    浅谈Java之终止继承:Final类和Fianl方法

    这篇文章主要介绍了Java之终止继承:Final类和Fianl方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-03-03
  • SonarQube安装、配置与使用教程图解

    SonarQube安装、配置与使用教程图解

    这篇文章主要介绍了SonarQube安装、配置与使用教程图解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-11-11
  • SpringMVC的五大核心组件用法及说明

    SpringMVC的五大核心组件用法及说明

    这篇文章主要介绍了SpringMVC的五大核心组件用法及说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-03-03
  • Java 的双重分发与 Visitor 模式实例详解

    Java 的双重分发与 Visitor 模式实例详解

    这篇文章主要介绍了Java 的双重分发与 Visitor 模式实例详解,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2018-07-07
  • Java四种常用线程池的详细介绍

    Java四种常用线程池的详细介绍

    今天小编就为大家分享一篇关于Java四种常用线程池的详细介绍,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-03-03
  • Java 11 正式发布,这 8 个逆天新特性教你写出更牛的代码

    Java 11 正式发布,这 8 个逆天新特性教你写出更牛的代码

    美国当地时间9月25日,Oracle 官方宣布 Java 11 (18.9 LTS) 正式发布,可在生产环境中使用!这是自 Java 8 后的首个长期支持版本
    2018-09-09
  • Java与Node.js利用AES加密解密出相同结果的方法示例

    Java与Node.js利用AES加密解密出相同结果的方法示例

    这篇文章主要介绍了Java与Node.js利用AES加密解密出相同结果的方法,文中给出了详细的示例代码,相信对大家的学习或者工作能带来一定的帮助,需要的朋友们下面来一起看看吧。
    2017-02-02
  • JAVA计算两个日期相差的实例

    JAVA计算两个日期相差的实例

    在java中我找了一下关于计算两个日期之间相差的天数方法有10多种实现方法,下面总结一下常用的几种计算两个日期之间相差的天数实例
    2013-11-11
  • idea导入jar包的详细图文教程

    idea导入jar包的详细图文教程

    这篇文章主要给大家介绍了关于idea导入jar包的详细图文教程,文中通过图文将导入的步骤介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2023-03-03

最新评论