点击上方蓝色“程序猿DD”,选择“设为星标”

回复“资源”获取独家整理的学习资料!

作者 | 巫师大人

来源 | blog.csdn.net/ysj4428/article/details/81195846

今天在开发中无意看到Integer包装类内部实现了Comparable接口,因此探查一下该接口作用:

查看API解释:

此接口强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序,类的 compareTo 方法被称为它的自然比较方法。

一、为什么需要实现这个接口呢?

首先看一下数据的例子:

String[] strArr = {"A","B","C","E","D"};
Arrays.sort(strArr);
for (String string : strArr) {System.out.print(string+";");
}

输出结果:

A;B;C;D;E;

从中我们可以看出sort方法对数据中的String字符串按照一定规则进行了排序,那为什么会排序呢?

查看String类我们可以看到:

public final class String
implements Serializable, Comparable, CharSequence{...
}

它也实现了Comparable接口。里面实现了compareTo方法,所以按照某种规则能够进行排序。

如果数组中的对象不是String而是自定义的类型呢?

public class ComparableDemo{public static void main(String[] args) {Object[] objArray = {new Person(20,"jack"),new Person(17,"tom"),new Person(27,"aj")};for (Object object : objArray) {System.out.print(object.toString());}Arrays.sort(objArray);for (Object object : objArray) {System.out.print(object.toString());}}
}
public class Person {private Integer age;private String name;public Person(int age,String name) {this.age = age;this.name = name;}@Overridepublic String toString() {return "Person [age=" + age + ", name=" + name + "]";}}

结果为:

Person [age=20, name=jack]Person [age=17, name=tom]Person [age=27, name=aj]
Exception in thread "main" java.lang.ClassCastException: interfacedemo.Person cannot be cast to java.lang.Comparableat java.util.ComparableTimSort.countRunAndMakeAscending(Unknown Source)at java.util.ComparableTimSort.sort(Unknown Source)at java.util.ComparableTimSort.sort(Unknown Source)at java.util.Arrays.sort(Unknown Source)at interfacedemo.ComparableDemo.main(ComparableDemo.java:18)

可以看到不进行排序打印是正常的,但是排序时报错了。因为系统无法知道使用什么规则进行排序。

我们存入字符串排序成功是因为String类已经实现Comparable接口,因此想要实现自定义对象比较同样需要实现该接口,其中的比较方法规则由我们自己设定。

二、接口简介

实现此接口的对象列表(和数组)可以通过 Collections.sort(和 Arrays.sort)进行自动排序。实现此接口的对象可以用作有序映射中的键或有序集合中的元素,无需指定比较器。

对于类 C 的每一个 e1 和 e2 来说,当且仅当 e1.compareTo(e2) == 0 与 e1.equals(e2) 具有相同的 boolean 值时,类 C 的自然排序才叫做与 equals 一致。注意,null 不是任何类的实例,即使 e.equals(null) 返回 false,e.compareTo(null) 也将抛出 NullPointerException。

建议(虽然不是必需的)最好使自然排序与 equals 一致。这是因为在使用自然排序与 equals 不一致的元素(或键)时,没有显式比较器的有序集合(和有序映射表)行为表现“怪异”。尤其是,这样的有序集合(或有序映射表)违背了根据 equals 方法定义的集合(或映射表)的常规协定。

例如,如果将两个键 a 和 b 添加到没有使用显式比较器的有序集合中,使 (!a.equals(b) && a.compareTo(b) == 0),那么第二个 add 操作将返回 false(有序集合的大小没有增加),因为从有序集合的角度来看,a 和 b 是相等的。

实际上,所有实现 Comparable 的 Java 核心类都具有与 equals 一致的自然排序。java.math.BigDecimal 是个例外,它的自然排序将值相等但精确度不同的 BigDecimal 对象(比如 4.0 和 4.00)视为相等。

从数学上讲,定义给定类 C 上自然排序的关系式 如下:

{(x, y)|x.compareTo(y) <= 0}。

整体排序的 商 是:

{(x, y)|x.compareTo(y) == 0}。

它直接遵循 compareTo 的协定,商是 C 的 等价关系,自然排序是 C 的 整体排序。当说到类的自然排序 与 equals 一致 时,是指自然排序的商是由类的 equals(Object) 方法定义的等价关系。

{(x, y)|x.equals(y)}。

此接口是 Java Collections Framework 的成员。

三、实现该接口

上面的例子进行修改,这里通过比较对象中的age属性进行排序

public class Person implements Comparable{private Integer age;private String name;public Person(int age,String name) {this.age = age;this.name = name;}@Overridepublic String toString() {return "Person [age=" + age + ", name=" + name + "]";}//进行方法重写@Overridepublic int compareTo(Object o) {Person p = (Person)o;return this.age - p.age;}}

结果打印:

Person [age=20, name=jack]Person [age=17, name=tom]Person [age=27, name=aj]
Person [age=17, name=tom]Person [age=20, name=jack]Person [age=27, name=aj]

最后附上该方法API描述:

compareTo

int compareTo(T o)

比较此对象与指定对象的顺序。如果该对象小于、等于或大于指定对象,则分别返回负整数、零或正整数。

实现类必须确保对于所有的 x 和 y 都存在 sgn(x.compareTo(y)) == -sgn(y.compareTo(x)) 的关系。(这意味着如果 y.compareTo(x) 抛出一个异常,则 x.compareTo(y) 也要抛出一个异常。)

实现类还必须确保关系是可传递的:(x.compareTo(y)>0 && y.compareTo(z)>0) 意味着 x.compareTo(z)>0。

最后,实现者必须确保 x.compareTo(y)==0 意味着对于所有的 z,都存在 sgn(x.compareTo(z)) == sgn(y.compareTo(z))。强烈推荐 (x.compareTo(y)==0) == (x.equals(y)) 这种做法,但并不是 严格要求这样做。一般来说,任何实现 Comparable 接口和违背此条件的类都应该清楚地指出这一事实。推荐如此阐述:“注意:此类具有与 equals 不一致的自然排序。”

在前面的描述中,符号 sgn(expression) 指定 signum 数学函数,该函数根据 expression 的值是负数、零还是正数,分别返回 -1、0 或 1 中的一个值。

参数:

o - 要比较的对象。

返回:

负整数、零或正整数,根据此对象是小于、等于还是大于指定对象。

抛出:

ClassCastException - 如果指定对象的类型不允许它与此对象进行比较。

往期推荐

为什么有些大公司技术弱爆了?

神奇的 SQL,Group By 真扎心,原来是这样!

Docker 禁止被列入美国“实体名单”的国家、企业、个人使用

一个被 CEO 逼疯的技术负责人的检讨书

王者荣耀为什么不使用微服务架构?

离职成为自由开发者的100天

星球限时拼团优惠进行中

???? ???? ???? ????

星球两大分享内容

我们常用的 Integer 内部为什么会去实现 Comparable 接口?相关推荐

  1. 好奇,我们常用的 Integer 内部为什么会去实现 Comparable 接口,他的作用是什么?...

    点击上方 好好学java ,选择 星标 公众号重磅资讯,干货,第一时间送达 今日推荐:分享一套基于SpringBoot和Vue的企业级中后台开源项目,这个项目有点哇塞!个人原创100W +访问量博客: ...

  2. http如何远程调用html页面,【Web】写个HTML页面去调试HTTP接口方便些

    现在越来越多的系统基本SOA的思想,业务由许多小系统通过远程调用的方式串连起来,其中HTTP的接口在远程调用的方式中颇为常见. 看过一些开发人员写完一些接口后,要么按照正常情况调用几次就交给调用方,要 ...

  3. easyui datagrid 中怎么选中所有页面的数据_学会这5个Excel中常用技巧,可以准时下班去摆摊了...

    Excel是大家常用的办公工具之一,虽说上手简单,但是想要精通还是要下一些功夫的.最近有些小伙伴在留言吐槽说Excel数据处理时很方便,但是操作起来还是挺费时间的,其实工作是离不开技巧的,今天要跟大家 ...

  4. 深入芯片内部,理解去耦电容的作用

    硬件十万个为什么 http://mp.weixin.qq.com/s?timestamp=1463301593&src=3&ver=1&signature=Kqrc177hW9 ...

  5. 常用正则,姓名匹配,去空格等

    中英文姓名正则匹配 中文姓名匹配的表达式为: var namereg = /^[\u4E00-\u9FA5]{2,4}$/; 表达式前段标识匹配中文字符,后面的2,4表示长度不小于2,不大于4,鉴于少 ...

  6. #SATA# 常用硬盘一览 之《协议、总线、接口》

    现实生活中,硬盘的种类可谓是多种多样,有时候搞得头晕.今天,我们总结一下.并不会涉及很深的知识点,只是比较初浅的认识. 硬盘想要正常工作,离不开三个条件:数据协议做沟通.传输总线做媒介.物理接口来接入 ...

  7. Java中,我自己定义的某个类,去实现某个接口,是否必须实现该接口的全部抽象方法呢?

    不一定,关键要看子类是否是抽象类. 如果子类是非抽象类,则必须实现接口中的所有方法:如果子类是抽象类,则可以不实现接口中的所有方法,因为抽象类中允许有抽象方法的存在! 一.抽象类定义 抽象类往往用来表 ...

  8. 常用显示器,硬盘都有哪几种接口

    目前,电脑显示器常见的接口主要有HDMI.DP.DVI.VGA等4种接口.显示器数据线性能排名:DP>HDMI>DVI>VGA.其中VGA是模拟信号,现在基本被主流接口所淘汰,DVI ...

  9. 常用3线4线cpu风扇显卡风扇接口定义(显卡风扇改造)

    帮朋友改造显卡风扇发现一个叫FG引脚,并不知是神马.总结如下: 4根线分别是GND.VCC.FG转速信号.PWM(调速). 位置可能不同. FG是转速信号,用于CPU侦测转速.转速=频率*30(4极风 ...

最新文章

  1. 转:c#委托事件实现窗体传值
  2. 200 switching to ascii mode_2020年12月英语四级阅读200篇第106篇:白云之乡—新西兰_四级...
  3. java 邮件 附件_java中javamail发送带附件的邮件实现方法
  4. 历史需要重写?AlexNet之前,早有算法完成计算机视觉四大挑战
  5. python manage.py syncdb Unknown command: 'syncdb'问题解决方法
  6. 7-9 计算摄氏温度 (5 分)
  7. 为什么面试总喜欢考算法题?
  8. 性能测试基础之JMeter聚合报告详解
  9. 应用虑镜特效时遇到浏览器权限问题
  10. Promise.then(a, b)与Promise.then(a).catch(b)问题详解
  11. 分子动力学模拟软件VMD的安装与使用
  12. LINUX矩阵键盘简单介绍,矩阵键盘程序流程图的详细介绍
  13. mall-accounts.json ES测试数据
  14. MM-DD-RRRR / MM-DD-YYYY 的区别 (Date format)
  15. 如何获取一个基因家族的所有小麦基因
  16. 云服务器需要防火墙吗?防火墙如何启用设置?
  17. ACM-ICPC 2018 焦作赛区网络预赛_J_ Participate in E-sports_Java大数开方
  18. 46岁新晋院士:我上研究生时,卸载了所有游戏
  19. 闲话乱侃——26字母软件开发语言命名是否用完了?
  20. 程序员如何修炼项目管理能力?

热门文章

  1. golang reflect Pointer 获取 传入的interface信息
  2. 内存分配的原理__进程分配内存有两种方式,分别由两个系统调用完成:brk和mmap(不考虑共享内存)
  3. Python3猜数字小游戏
  4. (五)OpenStack---M版---双节点搭建---Nova安装和配置
  5. linux非lvm分区在线扩容,怎么给不是LVM的根分区扩容
  6. gitlab 钩子 php,gitlab通过webhook.php自动部署标签
  7. golang中base64编码_MySQL中如何将字符串转为base64编码?
  8. idgenerator 会重复吗_终极版:分布式唯一ID的几种生成方案
  9. 代码 抠图_憋再PS抠图了,3行代码给你安排的明明白白!
  10. php 析构不执行,PHP析构方法 __destruct() 不触发的两个解决办法