zoukankan      html  css  js  c++  java
  • 面试官:说一下List排序方法

    1. 前言

    排序算是比较高频的面试题了,节前面试了的两家公司都有问到排序问题,整理后分享给大家(文末见总结)。

    通常我们想到实现排序就是 Collections 工具类的 sort() 方法,而 sort() 方法有两种:

    1. 直接调用 Collections.sort(List list) 方法进行排序(正序排序)。

    2. 调用 Collections.sort(List list,Comparator<? super T> c) ,自定义实现 Comparator 接口,重新 compareTo 方法。(相当于指定排序规则)

    下面来详细说明这两个方法。

    2. 什么是 Comparator ?

    在看方法之前,我们先来看看这个 Comparator 到底有什么用?

    Comparator ,中文意思为「比较器」,比较器的出现就是有些自定义类的 List 集合,不支持自身比较或者自身比较函数不能满足需求时,然后就可以写一个比较器来完成两个对象大小之间的比较,上边提到的方法 2 就是指定使用自定义 Comparator 来实现比较;而方法 1 是不指定 Comparator,不指定就会使用默认的排序方式(正序)。

    3. List 属性的不同

    List 排序一般分为「单属性排序」以及「实体属性排序」,单属性就是像是 String、Integer 等封装类(List list,List list),这些基本类型的封装类都已经实现了 Comparable 接口,并重写 compareTo() 方法,实体属性则就是我们自定义的实体类,然后想通过某些属性对象进行排序。

    单属性

    我们拿 Integer 类为例:

    List<Integer> list = new ArrayList<Integer>();

    如下为 Integer 内部的实现接口截图:

    所以,当我们直接调用 Collections.sort() 方法就可以实现排序效果(正序),举例说明:

    这就是单属性集合的排序,直接调用 Collections.sort() 接口就能完成排序。

    4. Comparable 和 Comparator 区别

    然后就可能有小伙伴说,哎?你不对劲...

    你上边说的是 Comparator 比较器,现在怎么 Integer 实现的是 Comparable 接口?Comparable 又是个什么鬼,这俩单词怎么长的这么像... 跟 Comparator 到底有啥区别呀?

    咳咳,不要慌...

    其实我们可以先看一下 Comparable 接口,该接口内部就只有一个 compareTo() 方法:

    再来看看 Comparator 接口,Comparator 接口的内部方法就比较多了,当然,在这我们就关注一下 compare() 方法即可:

    我们再回到 Integer 类,Integer 实现了 Comparable 接口,所以我们找一下 compareTo() 方法如下:

    如上方法,compareTo() 方法内部调用了 Integer 内部的 compare() 方法,通过注释我们发现。

    Integer 内部完成了数值的比较?

    其实到这也有点眉目了,好多文章有这么一个说法:Comparable 属于内比较器,Comparator 属于外比较器

    所谓的内比较器,我们还是以 Integer 为例,Integer 实现了 Comparable 接口,从 Integer 内部完成了数值的比较,也就是拿另外一个值跟自身比。

    所谓的外比较器,就是他会拿一个单独的类来完成比较,这个时候我们就可以拿方法二来看了:

    通过上面 List 的例子我们了解到了 Comparator 跟 Comparable 的使用,使用这两种方式都可以完成单属性的排序,区别就是内外部实现不同。

    排序规则:

    o1大于o2,返回正整数

    o1等于o2,返回0

    o1小于o3,返回负整数

    5. 实体属性排序

    因为平时工作中还是以实体属性 List 排序为主,并不会是直接 List,所以下面我们就通过一个 List 例子来分别通过 Comparator、Comparable 实现排序。

    User.java

    public class User {
      /**用户年龄**/
        private Integer age;

        public User(Integer age){
            this.age = age;
        }

        public Integer getAge() {
            return age;
        }

        public void setAge(Integer age) {
            this.age = age;
        }
    }
    5.1 Comparator 方式

    代码及执行截图:

    5.2 Comparable 方式

    我们需要让 User.java 实体实现一个 Comparable 接口,并重写 compareTo() 方法:

    public class User implements Comparable<User>{

        private Integer age;

        public User(Integer age){
            this.age = age;
        }

        public Integer getAge() {
            return age;
        }

        public void setAge(Integer age) {
            this.age = age;
        }

        @Override
        public int compareTo(User o) {
            // return this.age - o.getAge(); 正序
            return o.getAge() - this.age; // 倒序
        }
    }

    然后我们测试一下:

    ok,到这我们就实现了两种方式完成对实体属性对象的集合进行排序。

    6. 总结

    实现排序有两种方式:

    • 对象内部实现 Comparable 接口,重新 compareTo() 方法(区分正序倒序),完成内部比较,然后调用 Collections.sort() 排序。

    • 新建一个实现了 Comparator 接口的类,并重写 compare() 抽象方法

    如下转自:https://my.oschina.net/sdlvzg/blog/2243766

    JDK1.8之后可以很方便的对 List 进行排序,不用再写 Collections 类了。

    6.1 基础类型 List 排序
    /* 对数字进行排序 */
    List<Integer> nums = Arrays.asList(3,1,5,2,9,8,4,10,6,7);
    nums.sort(Comparator.reverseOrder()); /* reverseOrder倒序 */
    System.err.println("倒序:"+nums);

    nums.sort(Comparator.naturalOrder()); /* naturalOrder自然排序即:正序 */
    System.err.println("正序:"+nums);

    执行结果如下:

    6.2 对象List单属性排序
    List<User> listDevs = new ArrayList<User>(){{
        add(new User(10));
        add(new User(9));
        add(new User(20));
        add(new User(4));
    }};

    System.out.println("排序前:");
    /*JAVA8的写法,循环*/
    listDevs.forEach((developer)->System.out.println(developer.getAge()));

    /*第一个写法*/
    Collections.sort(listDevs, new Comparator<User>() {
        @Override
        public int compare(User o1, User o2) {
            return o1.getAge().compareTo(o2.getAge());
        }
    });
    /*第二个写法,JAVA8的写法,List 接口支持直接使用 sort 该方法,不再需要使用 Collections.sort 了
    listDevs.sort(listDevs, new Comparator<Developer>() {
       @Override
       public int compare(Developer o1, Developer o2) {
           return o1.getAge().compareTo(o2.getAge();
       }
    });*/

    /*第三个写法,Lambda写法,JAVA8的写法
    listDevs.sort((Developer o1, Developer o2)->o1.getAge().compareTo(o2.getAge()));*/

    /*第四个写法,Lambda写法,JAVA8的写法
    listDevs.sort((o1, o2)->o1.getAge().compareTo(o2.getAge()));*/

    /*第五写法,个Lambda写法,JAVA8的写法
    listDevs.sort(Comparator.comparing(Developer::getAge));*/

    /*第六写法,个Lambda写法,JAVA8的写法*/
    Comparator<User> ageComparator = (o1, o2)->o1.getAge().compareTo(o2.getAge());
    listDevs.sort(ageComparator);       /*按上面配置的顺序取值*/
    listDevs.sort(ageComparator.reversed());    /*按上面配置的顺序反向取值*/

    System.out.println("排序后:");
    /*JAVA8的写法,循环*/
    listDevs.forEach((developer)->System.out.println(developer.getAge()));

    博客园持续更新:https://www.cnblogs.com/niceyoo

    执行截图:

  • 相关阅读:
    Tip#66:你知道吗?如何在输入属性值时自动插入双引号
    使用 Apache MINA 开发高性能网络应用程序(转载)
    Faceted Search with Solr
    solr dataimport 数据导入源码分析 补充
    Apache Tika
    MiddlegenHibernate的配制和使用(jtds连接sqlserver数据库)
    汉语转拼音之pinyin4j(转载)
    使用Tika进行非结构化内容的读写1
    使用Java NIO编写高性能的服务器
    solr dataimport 数据导入源码分析(十)总结
  • 原文地址:https://www.cnblogs.com/niceyoo/p/13837835.html
Copyright © 2011-2022 走看看