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

执行截图:

面试官:说一下List排序方法相关推荐

  1. 面试官:private修饰的方法可以通过反射访问,那么private的意义是什么?

    欢迎关注方志朋的博客,回复"666"获面试宝典 Java,在一个类中,为了不让外界访问到某些属性和方法,通常将其设置为private,用正常的方式(对象名.属性名,对象名.方法名) ...

  2. 从面试官的角度分享一些后端校招经验

    1. 写在前面 我从去年年初开始在美团当校招面试官,参加了 17 届春招和 18 届秋招两届面试,总共就面试了五十多个人.本来我也就是刚开始学着当面试官,不该妄谈经验,但是因为最近换了一份工作,未来几 ...

  3. 面试官:聊一聊 Spring Boot 服务监控机制

    欢迎关注方志朋的博客,回复"666"获面试宝典 任何一个服务如果没有监控,那就是两眼一抹黑,无法知道当前服务的运行情况,也就无法对可能出现的异常状况进行很好的处理,所以对任意一个服 ...

  4. 一位资深Java的阿里系公司实战面试经验,套路还是面试官的多

    马老师说过,员工的离职原因很多,只有两点最真实: 1.钱,没给到位 2.心,受委屈了 以下是占小狼的一些实战面试经验分享,希望能帮助你们顺利拿到理想Offer! 项目经验 面试官在一开始会让你进行自我 ...

  5. 面试官问我JVM内存结构,我真的是

    面试官:今天来聊聊JVM的内存结构吧? 候选者:嗯,好的 候选者:前几次面试的时候也提到了:class文件会被类加载器装载至JVM中,并且JVM会负责程序「运行时」的「内存管理」 候选者:而JVM的内 ...

  6. 面试官问你是true还是false你可以最后反问他这个

    我们常常看到一些用==号判断是true还是false的面试题,今天就列出来几个,看看到底是true还是false,原因是什么. String s1 = "abc"; String ...

  7. 面试官:元素排序Comparable和Comparator有什么区别?

    作者 | 磊哥 来源 | Java面试真题解析(ID:aimianshi666) 转载请联系授权(微信ID:GG_Stone) 本文已收录<Java常见面试题>系列,Git开源地址:htt ...

  8. 一口气说出 6 种延时队列的实现方法,面试官满意的笑了

    这是我的第 193 期分享 作者 | 程序员内点事 来源 | 程序员内点事(ID:chegnxy-nds) 分享 | Java中文社群(ID:javacn666) 五一期间原计划是写两篇文章,看一本技 ...

  9. 实现时间排序_面试官:手撕十大排序算法,你会几种?

    推荐阅读: 去面试大厂被 Kafka 虐了,后悔没有早点看到这份Kafka手写笔记 面试阿里,京东,百度,快手归来,三年Java开发总结了这些经验 阿里,字节,腾讯,面试题都涵盖了,这一份Java面试 ...

  10. Arrays.sort() 为什么可以对 int 等数组进行排序?我跟面试官扯了半个小时 | 原力计划...

    作者 | TrueDei 责编 | 王晓曼 出品 | CSDN博客 前言 排序是在程序开发中最常用到的,最常见的就是针对一些数字进行排序.而现实中像商品的名字,订单的日期等进行排序.Java的JDK中 ...

最新文章

  1. 这份Kaggle Grandmaster的图像分类训练技巧,你知道多少?
  2. 深入掌握Java技术 EJB调用原理分析
  3. 又一款4800像素手机曝光:vivo V15 Pro
  4. 锁类型_ sys.dm_os_wait_stats
  5. java验证码实现简单_java实现简单的验证码功能
  6. 疑惑即新知——记一次reverse模板实现过程
  7. 运行时权限+读取系统联系人
  8. 这是属于格式的问题么?下划线的位置
  9. matlab 小波滤波器,matlab小波滤波器使用
  10. PAT (Basic Level) Practice1005 继续(3n+1)猜想
  11. Perl Print Win32 Console Windows 控制台 print Unicode 问题
  12. 黑客入侵手机的四种方法
  13. 基于springboot+mysql的房地产中介管理系统
  14. python分段函数图像画法_特殊分段函数的图像画法
  15. java 批量修改图片名称_java 批量修改文件名称
  16. native8081端口 react_ReactNative真机运行时8081端口被占用解决方案
  17. 终端不需要主机的服务器,要实现云桌面需要哪些硬件?云终端必不可少
  18. 如何用计算机排版打表格,PPT怎么利用表格来进行排版
  19. 阿里云国际站怎么注册?
  20. Maven –如何跳过单元测试

热门文章

  1. [css] 解释下 CSS sprites的原理和优缺点分别是什么
  2. [css] 用css画一个五边形和一个六边形
  3. [vue] 怎么解决vue打包后静态资源图片失效的问题?
  4. 工作285:判断绑定逻辑
  5. 工作41:解决vuex刷新数据丢失
  6. 前端学习(2095):数组里面得方法哪些
  7. 前端学习(1920)vue之电商管理系统电商系统之角色列表路由的切换
  8. 前端学习(1271):async/await处理多个异步请求
  9. 前端学习(872):注册事件兼容性处理
  10. 第八期:继美商务部拉黑多家中国公司后,MIT开始审查对华AI合作项目