详解Java中Comparable和Comparator接口的区别

发布于 2020-7-20|

复制链接

摘记: 详解Java中Comparable和Comparator接口的区别本文要来详细分析一下Java中Comparable和Comparator接口的区别,两者都有比较的功能,那么究竟有什么区别呢,感兴趣的Java开发者继续看下去吧。Comparable 简介 ..

详解Java中Comparable和Comparator接口的区别本文要来详细分析一下Java中Comparable和Comparator接口的区别,两者都有比较的功能,那么究竟有什么区别呢,感兴趣的Java开发者继续看下去吧。Comparable 简介Comparable 是排序接口。若一个类实现了Comparable接口,就意味着“该类支持排序”。  即然实现Comparable接口的类支持排序,假设现在存在“实现Comparable接口的类的对象的List列表(或数组)”,则该List列表(或数组)可以通过 Collections.sort(或 Arrays.sort)进行排序。此外,“实现Comparable接口的类的对象”可以用作“有序映射(如TreeMap)”中的键或“有序集合(TreeSet)”中的元素,而不需要指定比较器。Comparable 定义Comparable 接口仅仅只包括一个函数,它的定义如下:

```java

package java.lang;

import java.util.*;

public interface Comparable {

public int compareTo(T o);

}

```

说明:假设我们通过 x.compareTo(y) 来“比较x和y的大小”。若返回“负数”,意味着“x比y小”;返回“零”,意味着“x等于y”;返回“正数”,意味着“x大于y”。Comparator 简介Comparator 是比较器接口。我们若需要控制某个类的次序,而该类本身不支持排序(即没有实现Comparable接口);那么,我们可以建立一个“该类的比较器”来进行排序。这个“比较器”只需要实现Comparator接口即可。也就是说,我们可以通过“实现Comparator类来新建一个比较器”,然后通过该比较器对类进行排序。Comparator 定义Comparator 接口仅仅只包括两个个函数,它的定义如下:

```java

package java.util;

public interface Comparator {

int compare(T o1, T o2);

boolean equals(Object obj);

}

```

说明:(01) 若一个类要实现Comparator接口:它一定要实现compareTo(T o1, T o2) 函数,但可以不实现 equals(Object obj) 函数。为什么可以不实现 equals(Object obj) 函数呢? 因为任何类,默认都是已经实现了equals(Object obj)的。 Java中的一切类都是继承于java.lang.Object,在Object.java中实现了equals(Object obj)函数;所以,其它所有的类也相当于都实现了该函数。(02) int compare(T o1, T o2) 是“比较o1和o2的大小”。返回“负数”,意味着“o1比o2小”;返回“零”,意味着“o1等于o2”;返回“正数”,意味着“o1大于o2”。Comparator 和 Comparable 比较Comparable是排序接口;若一个类实现了Comparable接口,就意味着“该类支持排序”。而Comparator是比较器;我们若需要控制某个类的次序,可以建立一个“该类的比较器”来进行排序。我们不难发现:Comparable相当于“内部比较器”,而Comparator相当于“外部比较器”。我们通过一个测试程序来对这两个接口进行说明。源码如下:

```java

import java.util.*;

import java.lang.Comparable;

/**

* @desc "Comparator"和“Comparable”的比较程序。

* (01) "Comparable"

* 它是一个排序接口,只包含一个函数compareTo()。

* 一个类实现了Comparable接口,就意味着“该类本身支持排序”,它可以直接通过Arrays.sort() 或 Collections.sort()进行排序。

* (02) "Comparator"

* 它是一个比较器接口,包括两个函数:compare() 和 equals()。

* 一个类实现了Comparator接口,那么它就是一个“比较器”。其它的类,可以根据该比较器去排序。

*

* 综上所述:Comparable是内部比较器,而Comparator是外部比较器。

* 一个类本身实现了Comparable比较器,就意味着它本身支持排序;若它本身没实现Comparable,也可以通过外部比较器Comparator进行排序。

*/

public class CompareComparatorAndComparableTest{

public static void main(String[] args) {

// 新建ArrayList(动态数组)

ArrayList list = new ArrayList();

// 添加对象到ArrayList中

list.add(new Person("ccc", 20));

list.add(new Person("AAA", 30));

list.add(new Person("bbb", 10));

list.add(new Person("ddd", 40));

// 打印list的原始序列

System.out.printf("Original sort, list:%s\n", list);

// 对list进行排序

// 这里会根据“Person实现的Comparable接口”进行排序,即会根据“name”进行排序

Collections.sort(list);

System.out.printf("Name sort, list:%s\n", list);

// 通过“比较器(AscAgeComparator)”,对list进行排序

// AscAgeComparator的排序方式是:根据“age”的升序排序

Collections.sort(list, new AscAgeComparator());

System.out.printf("Asc(age) sort, list:%s\n", list);

// 通过“比较器(DescAgeComparator)”,对list进行排序

// DescAgeComparator的排序方式是:根据“age”的降序排序

Collections.sort(list, new DescAgeComparator());

System.out.printf("Desc(age) sort, list:%s\n", list);

// 判断两个person是否相等

testEquals();

}

/**

* @desc 测试两个Person比较是否相等。

* 由于Person实现了equals()函数:若两person的age、name都相等,则认为这两个person相等。

* 所以,这里的p1和p2相等。

*

* TODO:若去掉Person中的equals()函数,则p1不等于p2

*/

private static void testEquals() {

Person p1 = new Person("eee", 100);

Person p2 = new Person("eee", 100);

if (p1.equals(p2)) {

System.out.printf("%s EQUAL %s\n", p1, p2);

} else {

System.out.printf("%s NOT EQUAL %s\n", p1, p2);

}

}

/**

* @desc Person类。

* Person实现了Comparable接口,这意味着Person本身支持排序

*/

private static class Person implements Comparable{

int age;

String name;

public Person(String name, int age) {

this.name = name;

this.age = age;

}

public String getName() {

return name;

}

public int getAge() {

return age;

}

public String toString() {

return name + " - " +age;

}

/**

* 比较两个Person是否相等:若它们的name和age都相等,则认为它们相等

*/

boolean equals(Person person) {

if (this.age == person.age && this.name == person.name)

return true;

return false;

}

/**

* @desc 实现 “Comparable” 的接口,即重写compareTo函数。

* 这里是通过“person的名字”进行比较的

*/

@Override

public int compareTo(Person person) {

return name.compareTo(person.name);

//return this.name - person.name;

}

}

/**

* @desc AscAgeComparator比较器

* 它是“Person的age的升序比较器”

*/

private static class AscAgeComparator implements Comparator {

@Override

public int compare(Person p1, Person p2) {

return p1.getAge() - p2.getAge();

}

}

/**

* @desc DescAgeComparator比较器

* 它是“Person的age的升序比较器”

*/

private static class DescAgeComparator implements Comparator {

@Override

public int compare(Person p1, Person p2) {

return p2.getAge() - p1.getAge();

}

}

}

```

下面对这个程序进行说明。a) Person类定义。如下:

```java

private static class Person implements Comparable{

int age;

String name;

...

/**

* @desc 实现 “Comparable” 的接口,即重写compareTo函数。

* 这里是通过“person的名字”进行比较的

*/

@Override

public int compareTo(Person person) {

return name.compareTo(person.name);

//return this.name - person.name;

}

}

```

说明:(01) Person类代表一个人,Persong类中有两个属性:age(年纪) 和 name“人名”。

(02) Person类实现了Comparable接口,因此它能被排序。b) 在main()中,我们创建了Person的List数组(list)。如下:

```java

// 新建ArrayList(动态数组)

ArrayList list = new ArrayList();

// 添加对象到ArrayList中

list.add(new Person("ccc", 20));

list.add(new Person("AAA", 30));

list.add(new Person("bbb", 10));

list.add(new Person("ddd", 40));

```

c) 接着,我们打印出list的全部元素。如下:

```java

// 打印list的原始序列

System.out.printf("Original sort, list:%s\n", list);

```

d) 然后,我们通过Collections的sort()函数,对list进行排序。由于Person实现了Comparable接口,因此通过sort()排序时,会根据Person支持的排序方式,即 compareTo(Person person) 所定义的规则进行排序。如下:

```java

// 对list进行排序

// 这里会根据“Person实现的Comparable接口”进行排序,即会根据“name”进行排序

Collections.sort(list);

System.out.printf("Name sort, list:%s\n", list);

```

e) 对比Comparable和Comparator我们定义了两个比较器 AscAgeComparator 和 DescAgeComparator,来分别对Person进行 升序 和 降低 排序。e.1) AscAgeComparator比较器它是将Person按照age进行升序排序。代码如下:

```java

/**

* @desc AscAgeComparator比较器

* 它是“Person的age的升序比较器”

*/

private static class AscAgeComparator implements Comparator {

@Override

public int compare(Person p1, Person p2) {

return p1.getAge() - p2.getAge();

}

}

```

e.2) DescAgeComparator比较器它是将Person按照age进行降序排序。代码如下:

```java

/**

* @desc DescAgeComparator比较器

* 它是“Person的age的升序比较器”

*/

private static class DescAgeComparator implements Comparator {

@Override

public int compare(Person p1, Person p2) {

return p2.getAge() - p1.getAge();

}

}

```

f) 运行结果运行程序,输出如下:

```java

Original sort, list:[ccc - 20, AAA - 30, bbb - 10, ddd - 40]

Name sort, list:[AAA - 30, bbb - 10, ccc - 20, ddd - 40]

Asc(age) sort, list:[bbb - 10, ccc - 20, AAA - 30, ddd - 40]

Desc(age) sort, list:[ddd - 40, AAA - 30, ccc - 20, bbb - 10]

eee - 100 EQUAL eee - 100

```

java comparator相等_详解Java中Comparable和Comparator接口的区别相关推荐

  1. Java implement意思_详解JAVA中implement和extends的区别

    详解JAVA中implement和extends的区别 发布于 2020-4-14| 复制链接 摘记: 详解JAVA中implement和extends的区别extends是继承父类,只要那个类不是声 ...

  2. java sleep唤醒_详解Java中的线程让步yield()与线程休眠sleep()方法

    Java中的线程让步会让线程让出优先级,而休眠则会让线程进入阻塞状态等待被唤醒,这里我们对比线程等待的wait()方法,来详解Java中的线程让步yield()与线程休眠sleep()方法 线程让步: ...

  3. java runnable 异常_详解Java中多线程异常捕获Runnable的实现

    详解Java中多线程异常捕获Runnable的实现 1.背景: Java 多线程异常不向主线程抛,自己处理,外部捕获不了异常.所以要实现主线程对子线程异常的捕获. 2.工具: 实现Runnable接口 ...

  4. java 代码块_详解java中的四种代码块

    在java中用{}括起来的称为代码块,代码块可分为以下四种: 一.简介 1.普通代码块: 类中方法的方法体 2.构造代码块: 构造块会在创建对象时被调用,每次创建时都会被调用,优先于类构造函数执行. ...

  5. java static 函数_详解java中的static关键字

    Java中的static关键字可以用于修饰变量.方法.代码块和类,还可以与import关键字联合使用,使用的方式不同赋予了static关键字不同的作用,且在开发中使用广泛,这里做一下深入了解. 静态资 ...

  6. java 标量替换_详解jvm中的标量替换

    概述 通常在java中创建一个对象,大家都认为是在堆中创建. 在jdk6开始有逃逸分析,标量替换等技术,关于在堆中创建对象不再绝对. 关于标量替换,通过以下几点进行概述: 逃逸分析 标量替换是什么 测 ...

  7. java 引用传递_详解java的值传递、地址传递、引用传递

    详解java的值传递.地址传递.引用传递 一直来觉得对值传递和地址传递了解的很清楚,刚才在开源中国上看到一篇帖子介绍了java中的值传递和地址传递,看完后感受颇深.下边总结下以便更容易理解. 按照以前 ...

  8. java内部格式_详解java内部类的访问格式和规则

    详解java内部类的访问格式和规则 1.内部类的定义 定义一个类来描述事物,但是这个事物其中可能还有事物,这时候在类中再定义类来描述. 2.内部类访问规则 ①内部类可以直接访问外部类中的成员,包括私有 ...

  9. python java混合编程_详解java调用python的几种用法(看这篇就够了)

    java调用python的几种用法如下: 在java类中直接执行python语句 在java类中直接调用本地python脚本 使用Runtime.getRuntime()执行python脚本文件(推荐 ...

最新文章

  1. SpringBoot mybatis Interceptor分页实现
  2. NeurIPS 2021 | 寻找用于变分布泛化的隐式因果因子
  3. [转]Oracle11g链接提示未“在本地计算机注册“OraOLEDB.Oracle”解决方法
  4. 二项分布 , 多项分布, 以及与之对应的beta分布和狄利克雷分布
  5. rhcs集群套件—红帽6的高可用
  6. 字节AI LAB NLP算法二面凉+被捞后通过
  7. 基于selenium的钓鱼工具:关于ReelPhish神器的使用
  8. 英特尔贡献基于 Kubernetes 分布式深度学习平台:Nauta
  9. linux系统超好用的QQ
  10. python爬虫学习教程,短短25行代码批量下载豆瓣妹子图片
  11. MySQL——锁机制和数据库并发问题解决方案
  12. Retrofit使用教程(一)- Retrofit入门详解
  13. CorelDRAW2022矢量绘图软件老牌的矢量图形制作工具
  14. EOJ 2706 Fenwick Tree 树状数组找规律
  15. 电源输出端串入IN4007,测量正负电压,压降只有0.3v,为什么不是0.7v左右呢?
  16. Android 获取系统语言,区分简繁体中文
  17. 数学与计算机学院校友会,忆青春成长路 话数计奋斗情——数学与计算机学院校友会...
  18. 任何经历,都是一种积累
  19. 在企业访客管理中引入人脸识别系统有哪些应用?
  20. Everypixel –图库图片设计师的搜索引擎

热门文章

  1. [Java]如何安排任务间隔运行
  2. 适用于MongoDB和Mongometer的SpiderMonkey至V8
  3. 数据库和Webapp安全
  4. CometD:Java Web应用程序的Facebook类似聊天
  5. Spring和JSF集成:异常处理
  6. 处于RUNNABLE状态的Java线程未真正运行
  7. 使用SQL:2003 MERGE语句的奥术魔术
  8. Linux 命令之 chfn -- 修改用户信息
  9. Windows系统的MySQL目录结构
  10. Linux 命令之 rpmbuild -- 用于创建 rpm 格式的二进制软件包和源码软件包