java 中Comparable与Comparator详解与比较

发布时间 - 2026-01-11 00:34:12    点击率:

java 中Comparable与Comparator详解

今天查看TreeMap的源码,发现其键必须是实现Comparable或者Comparator的接口时产生了一些兴趣,比如在TreeMap中的put方法分别对Comparable和Comparator接口分别进行处理。那么疑问就来了,Comparable和Comparator接口的区别是什么,Java中为什么会存在两个类似的接口?

  Comparable和Comparator接口都是用来比较大小的,首先来看一下Comparable的定义:

 package java.lang;
import java.util.*;
public interface Comparable<T> {
  public int compareTo(T o);
}

  Comparator的定义如下:

package java.util;
public interface Comparator<T> {
  int compare(T o1, T o2);
  boolean equals(Object obj);
}

  Comparable对实现它的每个类的对象进行整体排序。这个接口需要类本身去实现(这句话没看懂?没关系,接下来看个例子就明白了)。若一个类实现了Comparable 接口,实现 Comparable 接口的类的对象的 List 列表 ( 或数组)可以通过 Collections.sort(或 Arrays.sort)进行排序。此外,实现 Comparable 接口的类的对象 可以用作 “有序映射 ( 如 TreeMap)” 中的键或 “有序集合 (TreeSet)” 中的元素,而不需要指定比较器。

  举例(类Person1实现了Comparable接口)

package collections;

public class Person1 implements Comparable<Person1>
{
  private int age;
  private String name;

  public Person1(String name, int age)
  {
    this.name = name;
    this.age = age;
  }
  @Override
  public int compareTo(Person1 o)
  {
    return this.age-o.age;
  }
  @Override 
  public String toString()
  {
    return name+":"+age;
  }
}

  可以看到Person1实现了Comparable接口中的compareTo方法。实现Comparable接口必须修改自身的类,即在自身类中实现接口中相应的方法。

  测试代码:

 Person1 person1 = new Person1("zzh",18);
    Person1 person2 = new Person1("jj",17);
    Person1 person3 = new Person1("qq",19);

    List<Person1> list = new ArrayList<>();
    list.add(person1);
    list.add(person2);
    list.add(person3);

    System.out.println(list);
    Collections.sort(list);
    System.out.println(list);

  输出结果:

[zzh:18, jj:17, qq:19]
[jj:17, zzh:18, qq:19]

  如果我们的这个类无法修改,譬如String,我们又要对其进行排序,当然String中已经实现了Comparable接口,如果单纯的用String举例就不太形象。对类自身无法修改这就用到了Comparator这个接口(策略模式)。

public final class Person2
{
  private int age;
  private String name;

  public Person2(String name, int age)
  {
    this.name = name;
    this.age = age;
  }

  @Override 
  public String toString()
  {
    return name+":"+age;
  }

  //getter and setter方法省略....
}

  如类Person2,这个类已经固定,无法进行对其类自身的修改,也修饰词final了,你也别想继承再implements Comparable,那么此时怎么办呢?在类的外部使用Comparator的接口。如下测试代码:

 Person2 p1 = new Person2("zzh",18);
    Person2 p2 = new Person2("jj",17);
    Person2 p3 = new Person2("qq",19);
    List<Person2> list2 = new ArrayList<Person2>();
    list2.add(p1);
    list2.add(p2);
    list2.add(p3);
    System.out.println(list2);
    Collections.sort(list2,new Comparator<Person2>(){

      @Override
      public int compare(Person2 o1, Person2 o2)
      {
        if(o1 == null || o2 == null)
          return 0;
        return o1.getAge()-o2.getAge();
      }

    });
    System.out.println(list2);

  输出结果:

[zzh:18, jj:17, qq:19]
[jj:17, zzh:18, qq:19] 

  这里(public static <T> void sort(List<T> list, Comparator<? super T> c) )采用了内部类的实现方式,实现compare方法,对类Person2的list进行排序。

  再譬如博主遇到的真实案例中,需要对String进行排序,且不区分大小写,我们知道String中的排序是字典排序,譬如:A a D排序之后为A D a,这样显然不对,那么该怎么办呢?同上(下面代码中的list是一个String的List集合):

 Collections.sort(list, new Comparator<String>()
    {
      @Override
      public int compare(String o1, String o2)
      {
        if(o1 == null || o2 == null)
          return 0;
        return o1.toUpperCase().compareTo(o2.toUpperCase());
      }
    });

  这样就可以实现不区分大小进行排序String的集合了,是不是很方便~

  细心的同学可能会有疑问,明明在Comparator接口中定义了两个方法,为什么继承的时候只实现了一个方法,难道要颠覆我对Java接口常识的理解了嚒?

  实际上,我们知道当一个类没有显式继承父类的时候,会有一个默认的父类,即java.lang.Object,在Object类中有一个方法即为equals方法,所以这里并不强制要求实现Comparator接口的类要实现equals方法,直接调用父类的即可,虽然你显式的实现了equals()方法 will be a better choice~

  在《Effective Java》一书中,作者Joshua Bloch推荐大家在编写自定义类的时候尽可能的考虑实现一下Comparable接口,一旦实现了Comparable接口,它就可以跟许多泛型算法以及依赖于改接口的集合实现进行协作。你付出很小的努力就可以获得非常强大的功能。

  事实上,Java平台类库中的所有值类都实现了Comparable接口。如果你正在编写一个值类,它具有非常明显的内在排序关系,比如按字母顺序、按数值顺序或者按年代顺序,那你就应该坚决考虑实现这个接口。

  compareTo方法不但允许进行简单的等同性进行比较,而且语序执行顺序比较,除此之外,它与Object的equals方法具有相似的特征,它还是一个泛型。类实现了Comparable接口,就表明它的实例具有内在的排序关系,为实现Comparable接口的对象数组进行排序就这么简单: Arrays.sort(a);

  对存储在集合中的Comparable对象进行搜索、计算极限值以及自动维护也同样简单。列如,下面的程序依赖于String实现了Comparable接口,它去掉了命令行参数列表中的重复参数,并按字母顺序打印出来:

public class WordList{
  public static void main(String args[]){
    Set<String> s = new TreeSet<String>();
    Collections.addAll(s,args);
    System.out.println(s);
  }
}

  Comparable 是排序接口;若一个类实现了 Comparable 接口,就意味着 “该类支持排序”。而 Comparator 是比较器;我们若需要控制某个类的次序,可以建立一个 “该类的比较器” 来进行排序。

  前者应该比较固定,和一个具体类相绑定,而后者比较灵活,它可以被用于各个需要比较功能的类使用。可以说前者属于 “静态绑定”,而后者可以 “动态绑定”。

  我们不难发现:Comparable 相当于 “内部比较器”,而 Comparator 相当于 “外部比较器”。

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!


# java 中Comparable与Comparator  # java 中Comparable与Comparator详解  # java 中Comparable与Comparator对比  # 实现了  # 是一个  # 绑定  # 对其  # 就可以  # 类中  # 都是  # 来了  # 会有  # 不太  # 你也  # 可以说  # 我对  # 依赖于  # 这句话  # 而不  # 这就  # 可以通过  # 希望能  # 采用了 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: 美食网站链接制作教程视频,哪个教做美食的网站比较专业点?  如何在浏览器中启用Flash_2025年继续使用Flash Player的方法【过时】  Windows10电脑怎么查看硬盘通电时间_Win10使用工具检测磁盘健康  国美网站制作流程,国美电器蒸汽鍋怎么用官方网站?  Laravel怎么为数据库表字段添加索引以优化查询  5种Android数据存储方式汇总  如何生成腾讯云建站专用兑换码?  javascript基本数据类型及类型检测常用方法小结  JS碰撞运动实现方法详解  如何快速重置建站主机并恢复默认配置?  php静态变量怎么调试_php静态变量作用域调试技巧【解答】  在Oracle关闭情况下如何修改spfile的参数  网站制作大概要多少钱一个,做一个平台网站大概多少钱?  动图在线制作网站有哪些,滑动动图图集怎么做?  JavaScript如何实现类型判断_typeof和instanceof有什么区别  Windows驱动无法加载错误解决方法_驱动签名验证失败处理步骤  如何确认建站备案号应放置的具体位置?  Laravel Octane如何提升性能_使用Laravel Octane加速你的应用  Android okhttputils现在进度显示实例代码  如何在HTML表单中获取用户输入并用JavaScript动态控制复利计算循环  Laravel如何使用Laravel Vite编译前端_Laravel10以上版本前端静态资源管理【教程】  Laravel怎么实现观察者模式Observer_Laravel模型事件监听与解耦开发【指南】  如何在香港服务器上快速搭建免备案网站?  网站制作公司哪里好做,成都网站制作公司哪家做得比较好,更正规?  linux写shell需要注意的问题(必看)  iOS中将个别页面强制横屏其他页面竖屏  Laravel如何使用Passport实现OAuth2?(完整配置步骤)  Python数据仓库与ETL构建实战_Airflow调度流程详解  ChatGPT 4.0官网入口地址 ChatGPT在线体验官网  Win11摄像头无法使用怎么办_Win11相机隐私权限开启教程【详解】  HTML透明颜色代码怎么让下拉菜单透明_下拉菜单透明背景指南【技巧】  Laravel中DTO是什么概念_在Laravel项目中使用数据传输对象(DTO)  免费制作统计图的网站有哪些,如何看待现如今年轻人买房难的情况?  Chrome浏览器标签页分组怎么用_谷歌浏览器整理标签页技巧【效率】  详解jQuery中的事件  合肥制作网站的公司有哪些,合肥聚美网络科技有限公司介绍?  Laravel如何配置任务调度?(Cron Job示例)  Laravel怎么集成Vue.js_Laravel Mix配置Vue开发环境  如何在搬瓦工VPS快速搭建网站?  Bootstrap CSS布局之列表  用yum安装MySQLdb模块的步骤方法  Laravel Admin后台管理框架推荐_Laravel快速开发后台工具  Python文件异常处理策略_健壮性说明【指导】  Laravel如何实现事件和监听器?(Event & Listener实战)  Mybatis 中的insertOrUpdate操作  在线制作视频的网站有哪些,电脑如何制作视频短片?  网站制作免费,什么网站能看正片电影?  零基础网站服务器架设实战:轻量应用与域名解析配置指南  网站广告牌制作方法,街上的广告牌,横幅,用PS还是其他软件做的?  C++时间戳转换成日期时间的步骤和示例代码