

面试官:你知道Comparable 和 Comparator 的区别吗?我:巴拉巴拉 - JavaBuild
source link: https://www.cnblogs.com/JavaBuild/p/18030265
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

面试官:“我们在Java的集合和数据结构中都离不开比较器,请你聊一聊Comparable 和 Comparator 这两种的区别吧”
内心活动:“上来就这么直接吗,那些ArrayList,HashMap都不问呀,好,既然如此,那让我来征服你吧,面试官大人!”
我:“好滴!巴拉巴拉~”
Comparable
Comparable是java.lang包下的一个接口,其内部构造非常简单,只有一个compareTo()方法,使用起来也很简单,直接实现接口,重写方法即可。
【源码解析1】
public interface Comparable<T> { int compareTo(T t);}
【代码示例1】
定义一个Person类,重写compareTo()方法,用以比较Person对象的年龄大小
@Datapublic class Person implements Comparable<Person>{ private int age; private String name; public Person(int age, String name) { this.age = age; this.name = name; } @Override public int compareTo(Person o) { return this.getAge()-o.getAge(); }}
写一个测试类,调用
【代码示例2】
public class Test { public static void main(String[] args) { Person xiaoming = new Person(18, "小明"); Person xiaohua = new Person(20, "小华"); if(xiaoming.compareTo(xiaohua) <0){ System.out.println(xiaoming.getName()+"更年轻"); }else{ System.out.println(xiaohua.getName()+"更年轻"); } }}
输出:
小明更年轻
以上是我们自己实现的Comparable接口,其实在Java中像String、基本类型的包装类在底层也都实现了这个接口,并重写了compareTo()方法,因此,他们也拥有比较属性。
【代码示例3】
Integer in1 = 2;Integer in2 = 3;System.out.println(in1.compareTo(in2));
输出:
-1
Comparator
Comparator 是java.util包中的一个接口,它的底层构造相比较Comparable要复杂的多了,不过我们主要还是关注其中的compare()方法。
【源码解析2】
public interface Comparator<T> { int compare(T o1, T o2); boolean equals(Object obj);}
讲到这里,我们可以对比Comparable接口进行阐述,解释一下为什么有个相似的比较排序接口,还要设计Comparator,因为很多时候我们并不想破坏原始类的结构,比如Person类中,我们只需要它拥有age和name,不想写一些实现方法在其中,这个时候就需要Comparator啦!
1)首先,我们可以为Person类自定义一个比较器
【代码示例4】
public class PersonalComparator implements Comparator<Person> { @Override public int compare(Person o1, Person o2) { return o1.getAge() - o2.getAge(); }}
2)然后,我们写一个测试类使用一下看看,其实这里面要借助一个List的sort()进行调用,我们直接手撕代码,这样更容易理解!
【代码示例5】
public class Test { public static void main(String[] args) { Person xiaoming = new Person(20, "小明"); Person xiaohua = new Person(18, "小华"); ArrayList<Person> objects = new ArrayList<>(); objects.add(xiaoming); objects.add(xiaohua); objects.sort(new PersonalComparator()); for (Person object : objects) { System.out.println(object.getName()); } }}
输出:
小华小明
我们跟进去看一下sort()方法的底层源码,会发现,在它的底层实际上Arrays.sort进行数组排序,而使用的比较器,就是我们传入的自定义PersonalComparator 对象。
【源码解析3】
public void sort(Comparator<? super E> c) { // 保存当前队列的 modCount 值,用于检测 sort 操作是否非法 final int expectedModCount = modCount; // 调用 Arrays.sort 对 elementData 数组进行排序,使用传入的比较器 c Arrays.sort((E[]) elementData, 0, size, c); // 检查操作期间 modCount 是否被修改,如果被修改则抛出并发修改异常 if (modCount != expectedModCount) { throw new ConcurrentModificationException(); } // 增加 modCount 值,表示队列已经被修改过 modCount++;}
好了,解释到这里,我想已经足以令面试官满意了,两者的底层实现,如何使用都进行了详细的阐述,但是!如果你足够自信,可以进一步延伸出Collections.sort(),它的底层其实也是比较器,只不过这个比较器没有特殊的实现,采用的自然排序规则(升序)。源码就不在这里展示了,爱钻研的小伙伴可以自己去看哈。
1、一个类实现了 Comparable,意味着该类的对象可以直接进行比较(排序)但比较(排序)的方式只有一种,很单一。 2、一个类如果想要保持原样,又需要进行不同方式的比较(排序),就可以定制比较器(实现 Comparator 接口)。 3、Comparable 接口在 java.lang 包下,而 Comparator 接口在 java.util 包下。
如果本篇博客对您有一定的帮助,大家记得留言+点赞+收藏呀。原创不易,转载请联系Build哥!

Recommend
-
40
介绍Comparable<T>接口和Comparator<T>接口都是JDK中提供的和比较相关的接口。使用它们可以对对象进行比较大小,排序等操作。这算是之后排序的先导知识吧。Comparable,字面意思是“可以比较的”,所以实现它的类的多个实例应该可以相互比较“大小”或者“...
-
106
在逛 programcreek 的时候,我发现了一些专注细节但价值连城的主题。比如说:Java 的 Comparable 和 Comparator 是兄弟俩吗?像这类灵...
-
31
Comparable和Comparator兄弟俩长得是真像。但是,需要注意下,使用中它们还是有不少区别的。下面,就一探究竟吧。 一、Comparator 做过集合排序的童鞋应该知道,可以使用Collections.sort方法对集合进行排序。我们点进去Co...
-
12
集合工具类Collections指南,以及Comparable和Comparator排序详解 原创 共饮一杯无...
-
8
第十一章《Java实战常用类》第9节:Comparable接口和Comparator接口 精选 原创 对事物进行比较往往是希望对它们进行排序,因此排...
-
7
之前更新了不少Java的基础知识,比如Java的类、对象、基础类型、关键字、序列化、泛型、值传递等等,今天要上点深度了,来聊一聊Java中的 反射 ! 所谓反射,就是在运行时分析、检查和操作类、接口、方法、...
-
9
在《深入剖析Java中的反射,由浅入深,层层剥离!》这篇文章中我们讲反射时,曾提到过Java的动态代理中使用了反射技术,那么好,今天我们要就着反射的索引,来学习一下Java中的代理!
-
2
Promise, async, await实现异步编程,代码详解
-
5
面试官:小伙子请聊一聊Java中的精灵线程? 我:什么?精灵线程?啥时候精灵线程? 面试官:精灵线程没听过?那守护线程呢? 我:守护线程知道,就是为普通线程服务的线程嘛。 面试官:没了?守护线程的特点,怎么使用,需要注意啥,Java中...
-
6
在线程的生命周期中,不同状态之间切换时,可以通过调用sleep()、wait()、join()、yield()等方法进行线程状态控制,针对这一部分知识点,面试官们也会做做文章,比如问你这些方法的作用以及之间的区别。 那么今天我们就一起来总结一下这几个方法的作用及区别...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK