似懂非懂的Comparable与Comparator
jdk1.8.0_144
一知半解写代码, 集合排序用个啥。 抄起键盘胡乱打, 似懂非懂最可怕。
Comparable与Comparator都是用于集合的排序,对于大多数人来说Comparator可能略微比Comparable要熟悉一点,类似下面这几句代码的使用频率应该是最高的。
Collections.sort(list, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.compareTo(o2);
}
});
这是一段对集合排序的代码。
对于集合排序时比较器的使用往往止步于此,以至于更为深层次的使用似懂非懂,更为复杂的排序不知所措。
Comparable用于集合内部定义的方法实现的排序,Comparator用于集合外部实现的排序。
我们从Collections.sort的两个重载方法开始
public static <T extends Comparable<? super T>> void sort(List<T> list)
public static <T> void sort(List<T> list, Comparator<? super T> c)
这两个方法都是泛型方法,第一个方法只传递一个List参数进行排序,第二个方法传递一个List参数加上一个Comparator比较器。
public static <T extends Comparable<? super T>> void sort(List<T> list)
Collections.sort方法用于对List集合进行排序,思考一个问题,这个只有一个参数的List如何进行排序呢?它是按照怎样的规则进行排序呢?答案就在这个泛型方法的泛型类型之中“<T extends Comparable<? super T>>”,List集合中的元素需要实现Comparable接口,Comparable接口也是一个泛型,并要求它的泛型类型需要是集合中的元素的超类(或自身)。重点在于——集合中的元素需要是实现Comparable接口。也就是说在使用Collections.sort(List)这个方法对集合中的元素进行排序时,需要集合中的元素实现了Comparable接口,这才能进行排序。
public static <T> void sort(List<T> list, Comparator<? super T> c)
这个方法同样是一个泛型方法,与上面的方法不同的是对集合中的元素类型并没有做限制,要对这个集合进行排序需要指定一个Comparator比较器,这个比较器的泛型类型需要是集合元素的超类(或自身)。
通过上面这两个方法比较容易的能得出一个浅显的结论,Comparable和Comparator都是用于比较、排序,如果元素自身已经实现了Comparable接口,则可以利用它自身进行比较排序,如果元素自身没有实现Comparable接口,则可以利用外部实现Comparator比较器对元素进行比较排序。这也就是前面提到的Comparable用于集合内部定义的方法实现的排序,Comparator用于集合外部实现的排序。 接着来看Comparable接口和Comparator接口。
接着来看Comparable接口和Comparator接口。
Comparable
public int compareTo(T o)
这个接口只定义了一个compareTo方法,在很多“值类型”的数据类型,例如String、Integer、Long等已经实现了这个接口。
对于这个方法和equals方法有类似的地方,equals强调的更多是相等于否,而compareTo强调更多的比较,如果x < y,则返回-1;x = y,则返回0;x > y,则返回1。实现这个方法时同样需要遵循几个规则:
- 自反性,如果x <y ,那么x.compareTo(y)返回-1,同理y.compareTo则返回1;
- 传递性,如果x.compareTo(y)返回-1,y.compareTo(z)返回-1,则x.compareTo(z)也应该返回-1;
- 同一性,如果x.compareTo(y)返回0(x = y),那么若x.compareTo(z)返回-1时,y.compareTo(z)也应该返回-1。
有兴趣的可以查看String类中对于compareTo方法的实现,它的排序规则是将字符串转换为字符数组逐个按照字典序排序。
Comparator
int compare(T o1, T o2)
boolean equals(Object obj)
这个接口在JDK8中对它进行了较大的改进,在JDK8之前只包含上面两个方法,而JDK8则达到了18个方法,其中都是接口的default方法,和static静态方法,所以并不需要在实现时额外实现。
在JDK8中该类添加了@FunctionalInterface函数式接口的注解,函数式接口表明在接口中只含有一个方法作为Lambda表达式的数据类型,在《JDK8的新特性——Lambda表达式》中有提到,Java中定义如果覆盖了Object中的方法则不算,所以在Comparator接口中只有一个compare方法。对于@FunctionalInteface注解可加不可加,加上只是为了让编译器做更好的检查,要求只能定义一个方法,不加编译器便不对此进行检查。
compare方法和compareTo方法类似,它同样需要满足上面提到的:自反性、传递性、同一性。并且它强调,不必严格满足“(compare(x, y)==0) == (x.equals(y))”,当然最好说明白。
对于这个类,更多的是需要理解学习它所运用的设计模式——策略模式。策略模式,不改变对象自身,而是用另一个对象来改变它的行为。例如,超市减价操作,有10件商品需要统一降价1半进行处理,我们可以在这10件商品的价格上全部做修改减少至它的一半,10件好处理,如果N件呢,甚至我们还需要对其进行降价呢?此时我们则可以使用一种“策略”——商品全部打5折。这就是利用另外一个对象来改变一个对象的行为,而不是简单粗暴地修改原有对象。说回此处,如果List中的元素本身没有实现Comparable接口,但我们需要对它进行排序,我们可以对原有对象进行修改让它实现Comparable接口,但凡涉及修改代码都不优美,此时我们则可以利用策略模式,也就是实现一个Comparator接口对集合中的元素进行排序。
这是一个能给程序员加buff的公众号

似懂非懂的Comparable与Comparator的更多相关文章
- Java中Comparable与Comparator的区别
相同 Comparable和Comparator都是用来实现对象的比较.排序 要想对象比较.排序,都需要实现Comparable或Comparator接口 Comparable和Comparator都 ...
- 对象比较器:Comparable和Comparator
在进行对象数组排序的过程中需要使用到比较器,比较器有两个:Comparable和Comparator ①.java.lang.Comparable:是在类定义是时候默认实现好的接口,里面提供有一个co ...
- Java中Comparable和Comparator接口区别分析
Java中Comparable和Comparator接口区别分析 来源:码农网 | 时间:2015-03-16 10:25:20 | 阅读数:8902 [导读] 本文要来详细分析一下Java中Comp ...
- Comparable和Comparator的区别
Comparable Comparable可以认为是一个内比较器,实现了Comparable接口的类有一个特点,就是这些类是可以和自己比较的,至于具体和另一个实现了Comparable接口的类如何比较 ...
- Java中Comparable和Comparator区别小结
一.Comparable简介 Comparable是排序接口.若一个类实现了Comparable接口,就意味着该类支持排序.实现了Comparable接口的类的对象的列表或数组可以通过Collecti ...
- Java 中 Comparable 和 Comparator 比较
Java 中 Comparable 和 Comparator 比较 目录: Comparable Comparator Comparable 和 Comparator比较 第二个例子 之 Compar ...
- Comparable与Comparator
转载 Comparable与Comparator的区别 (转载) Comparable & Comparator 都是用来实现集合中元素的比较.排序的,只是 Comparable 是在集合内部 ...
- Java中的TreeMap、Comparable、Comparator
我们知道HashMap的存储位置是按照key这个对象的hashCode来存放的,而TreeMap则是不是按照hashCode来存放,他是按照实现的Comparable接口的compareTo这个方法来 ...
- 比较器comparable与comparator的使用
在Java学习和使用里,工具类与算法类(collections和Arrays)也是我们使用比较多的,在它们里面就包含了comparable与comparator这两种比较器. 一.比较器的分类与概念 ...
随机推荐
- 从零开始学习前端JAVASCRIPT — 5、JavaScript基础BOM
1:BOM(Browser Object Model)概念 window对象是BOM中所有对象的核心. 2:window属性(较少用) self:self代表自己,相当于window. windo ...
- 从零开始学习前端开发 — 10、HTML5新标签及表单控件属性和属性值
一.html5新增标签 1.结构性标签 header 定义网页的头部 nav 定义网页的导航 footer 定义网页的底部 section 定义网页的某个区域 article 定义网页中的一篇文章 a ...
- svn冲突文件解决方法
svn冲突文件解决方法 工具/原料 svn客户端 方法/步骤 1 通过SVN客户端更新需要的文件,如果出现有感叹号的文件,找到出现感叹号的文件. 2 选择感叹号文件,即冲突文件,单击鼠标右键对冲突文件 ...
- 安装mysql后运行.net程序出错
安装mysql后运行.net程序出错: 出错位置:C:\Windows\Microsoft.NET\Framework\v4.0.30319\Config\machine.config 出错信息:未 ...
- mysql字符集问题 错误代码: 1267 Illegal mix of collations (utf8_general_ci,IMPLICIT) and (utf8_croatian_ci,IMPLICIT) for operation '='
一般是多表或跨库表查询导致出现的问题,其原因是两张表的字符集不一样导致的,那为什么两张表的字符集会不一样?这是由于架构师或者开发人员在建表的时候不小心选错字符集的原因导致的. 那好我们把两张表(或两个 ...
- Flex: Holy Grail
Flex:Holy Grail <html> <head> <style type="text/css"> body,div,header,ma ...
- 20170505 PHP实践中知识点
1.json_encode 不转义 2.empty() 与 isset() 区别 在使用 php 编写页面程序时,我经常使用变量处理函数判断 php 页面尾部参数的某个变量值是否为空,开始的时候我习惯 ...
- 设置PATH和CLASSPATH
每天玩java的,如果连这门语言背景一点都熟悉的话,说出去真的是挺丢人的一件事情. 首先,java具有最强大的2个特点:功能强大,简单易用.出去android不说,这门语言衍生出太多的开源框架了,这也 ...
- java 中的instanceof
java 中的instanceof 运算符是用来在运行时指出对象是否是特定类的一个实例.instanceof通过返回一个布尔值来指出,这个对象是否是这个特定类或者是它的子类的一个实例. 用法:resu ...
- nginx配置中root与alias的区别
nginx指定文件路径有两种方式root和alias,这两者的用法区别,使用方法总结了下,方便大家在应用过程中,快速响应.root与alias主要区别在于nginx如何解释location后面的uri ...