5 分钟搞定 Java Comparable 接口

Comparable接口时用来干什么的呢?

我们应该如何对事物进行比较和排序?这问题听上去有点莫名其妙,但我希望你认真考虑一下。比方说,我们有一组苹果:

例1

我们要怎样对它们进行排序呢?我们希望通过重量进行排序吗?如果是的话,排序是从最轻到最重还是从最重到最轻?当我们对它们进行排序的时候,我们需要反复比较两个苹果的重量,直到正确地排好所有的苹果。苹果1比苹果2重?那它比苹果3重吗?我们需要不断比较,直到完成排序。Comparable接口可以帮助我们实现这一目标。Comparable本身不能对对象进行排序,但接口定义的方法 int compareTo(T)可以。

compareTo(T)如何工作

让我们通过使用compareTo()方法来看看哪个苹果更重,开始吧。

例2

compareTo()方法的工作原理是返回一个int值——或正,或负,或为零。它通过调用作为参数的对象来比较对象。负数表示调用的对象比参数“轻”。如果我们用大小来比较苹果,那么上面的调用会返回一个负数,例如-400,因为红苹果比青苹果小。如果两个苹果重量相等,那么调用将返回0。如果红苹果更重,那么compareTo()将返回一个正数,例如68。

compareTo()的灵活性

如果我们反复调用上面的compareTo()方法,那么我们可以通过大小来排序,这很棒,但并非故事的结束。如果我们想通过颜色来给苹果排序呢?抑或是重量?我们也可以做到。关键是,我们的客户——让我们叫他胖子农夫(见例3),需要在我们开始开发之前精确定义需要如何对苹果进行排序。

例3

他可以通过回答这两个问题来做到这一点:

  1. 他希望苹果如何进行排序?他希望我们比较什么特征?
  2. 在那样的环境中,“小于”,“等于”和“大于”指的是什么意思?

也可以使用多个特征,这个后面我们会讲。

例1:通过重量排序苹果

在第一个例子中,我们将通过重量对苹果排序。只需要一行代码。

例4

上面的代码行可以为我们做到所有的排序工作,只要我们事先定义好如何对苹果进行排序(这就需要多行代码了)。

让我们开始写苹果类吧。

例5

这是Apple类的第一个版本。由于我们使用的是compareTo方法,并且正在排序苹果,所以我实现了Comparable接口。在这第一个版本中,我们通过重量比较对象。在我们的compareTo()方法中,我们写一个if条件,说明如果这个苹果的重量小于其他的苹果,那么返回一个负数,为了保持简单,我们假定它为-1。请记住,这意味着这个苹果轻于Apple ‘other’。在第二个if语句中,我们要说明,如果苹果重量相等,那么返回一个0。当然,如果这个苹果既不是更轻,又不是一样重,那就只能比其他苹果更重了。在这种情况下,我们返回一个正数,假定为1。

例2:通过多个特征排序苹果

正如我前面提到的,我们还可以使用compareTo()比较多个特征。比方说,我们第一通过品种排序苹果,但如果两个苹果是同一品种,那么我们就按颜色排序。最后,如果这两个特性相同,那么我们将按重量排序。虽然我们可以手动实现这件事,就像我在最后一个例子中做的那样,但是其实可以用一种简洁得多的方式实现。一般来说,最好是重用现有的代码,而不是自己写。我们可以在Integer、String和枚举类中使用compareTo方法来比较值。由于我们没有使用Integer对象,用了int,所以我们不得不使用来自于Integer包装器类的一个静态的helper方法来比较两个值。

例6

在例6中,我们比较了客户指定的苹果的第一特性,它们的品种。如果compareTo()调用的结果为非零,那么我们返回值。否则,我们调用另一个compareTo()直到得到一个非零值,或者直到已经比较完这三个特征。尽管此代码可以工作,但它不是最有效或干净的解决方案。在例3中,我们重构我们的代码,使其更简单。

例7

正如你所看到的,这大大减少了代码,并且每一次比较只要一行代码。如果一个compareTo()调用的结果是零,那么我们就转移到下一个相同if语句的比较中。顺便说一句,这是成为Clean Coder的一个很好的例子。通常情况下,你不需要立即写出干净的代码;你可以从一个粗略的想法开始,使其可以工作,然后不断改进,直到你尽可能得让它干净就可以了。

Comparable,hashCode以及Equals

你可能会注意到compareTo()看起来有点像hashCode()和equals()方法。但是,它们有一个重要的区别。对于hashCode()和equals()方法,比较个体属性的顺序不影响返回的值,但是,在compareTo()中,通过你比较对象的顺序来定义对象的顺序。

结论

在结论中我只想强调Comparable接口是多么的重要。它既用于java.util.Arrays,也用于java.util.Collections实用程序类,来排序元素和搜索排序集合中的元素。使用TreeSet和Tree Map,就更简单了——想要它们会自动排序必须实现Comparable接口的元素。

原文发布于微信公众号 - java一日一条(mjx_java)

原文发表时间:2016-11-11

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏coding for love

JS进阶系列

在JS入门难点解析系列中,我们对JS的一些重要概念,比如:作用域,作用域链,原型,原型链,继承,活动对象,this,执行环境,变量声明,函数声明等进行了详细的分...

821
来自专栏程序员互动联盟

【面试宝典】final 关键字

面试官:你刚毕业? 小白:还没有,大四学校没有课,就想着出来找实习单位多学习学习。 面试官:很好嘛年轻人,早点出来锻炼确实是快速提高自己的一个好方法,那咱们就简...

3383
来自专栏CodingToDie

Python学习(八):类和对象 以另一种思维看待世界

第8 章 类和对象 以另一种思维看待世界 对世界万物的状态与行为进行归纳与分类,以此分析个体与个体间的相互作用与影响方法。 Table of Contents ...

3727
来自专栏趣谈编程

归并排序

面试官: 聊聊归并排序 归并排序是建立在归并操作的一种高效的排序方法,该方法采用了分治的思想,比较适用于处理较大规模的数据,但比较耗内存,今天我们聊聊归并排序 ...

4157
来自专栏Golang语言社区

Golang语言社区--Go语言基础第二节变量

大家好,我是社区主编cserli(或者大家叫我彬哥也可以),Golang语言社区一直致力于Go语言相关技术干货的分享,希望初学者可以少走些弯路,我...

62527
来自专栏C语言C++游戏编程

C语言内置运算符丰富到令人头皮发麻,C语言基础教程之运算符篇

运算符是告诉编译器执行特定数学或逻辑函数的符号。C语言内置运算符丰富,并提供以下类型的运算符 -

1291
来自专栏java一日一条

5 分钟搞定 Java Comparable 接口

还有一个不错的视频(https://marcus-biel.com/java-comparable-interface-video-tutorial/)。

1104
来自专栏青青天空树

成绩大排队

其中姓名和学号均为不超过10个字符的字符串,成绩为0到100之间的一个整数,这里保证在一组测试用例中没有两个学生的成绩是相同的。

862
来自专栏LeetCode

LeetCode <dp>64. Minimum Path Sum

Given a m x n grid filled with non-negative numbers, find a path from top left t...

1640
来自专栏NetCore

驳“反驳老赵之“伪”递归”

晚上看到鹤冲天的“反驳老赵之“伪”递归”,大概看了一下,主要是反驳老赵提出的“伪”递归的概念,特别是“伪”,看起来说的都很有道理,但我个人认为,老赵说的没有错,...

2275

扫码关注云+社区

领取腾讯云代金券