Java 中的自定义排序实现方法

文章目录

  • Java 中的自定义排序实现方法
    • 1. 使用自定义比较器对数组进行排序
      • 1.1 实现`Comparator`接口
      • 1.2 使用`Arrays.sort()`方法
      • 1.3 匿名内部类
      • 1.4 代码结果
    • 2. 使用自定义比较器对集合进行排序
      • 2.1 实现`Comparable`接口
      • 2.2 使用`Collections.sort()`方法
      • 2.3 使用Lambda表达式
      • 2.4 代码结果
    • 比较器的排序规则
      • 返回值规则
      • 举例
      • 注意点
    • 比较两个接口
      • `Comparable` 接口
      • `Comparator` 接口
      • 总结
    • 比较两个方法
      • Arrays.Sort ()
      • Collections.Sort ()
      • 关键区别

Java 中的自定义排序实现方法

在Java中,排序是经常需要用到的操作,Java提供了两种通用的排序方法:

  • Arrays.sort()方法: 适用于基本类型数组和对象数组。
  • Collections.sort()方法: 适用于实现了Comparable接口的集合。

但是有时我们想自定义排序的规则,就要使用这两种方法的重载版本,传入自定义的比较器(Comparator)对象。

1. 使用自定义比较器对数组进行排序

1.1 实现Comparator接口

要自定义数组的排序规则,首先需要创建一个类,实现Comparator接口。该接口只有一个方法:

int compare(T o1, T o2);

该方法用于比较两个元素,并返回一个整数:

  • 如果o1小于o2,则返回-1。
  • 如果o1等于o2,则返回0。
  • 如果o1大于o2,则返回1。

例如,要按照字符串的长度对字符串数组进行排序,可以定义如下比较器:

class StringLengthComparator implements Comparator<String> {@Overridepublic int compare(String s1, String s2) {return s1.length() - s2.length();}
}

1.2 使用Arrays.sort()方法

有了自定义比较器之后,就可以使用Arrays.sort()方法对数组进行排序。该方法的重载版本接受一个数组和一个比较器对象作为参数:

Arrays.sort(array, comparator);

例如,要按照字符串的长度对字符串数组strArray进行排序,可以使用如下代码:

String[] strArray = {"abc", "12345", "abcdef"};
StringLengthComparator comparator = new StringLengthComparator();
Arrays.sort(strArray, comparator);

1.3 匿名内部类

如果只是为了简单的排序需求,可以使用匿名内部类来实现Comparator接口。例如,要按照字符串的自然顺序对字符串数组进行排序,可以使用如下代码:

Arrays.sort(strArray, new Comparator<String>() {@Overridepublic int compare(String s1, String s2) {return s1.compareTo(s2);}
});

1.4 代码结果

class StringLengthComparator implements Comparator<String> {@Overridepublic int compare(String s1, String s2) {return s1.length() - s2.length(); // to sort in ascending order}}public static void compareStrings2() {String[] strArray = { "12345", "abc", "abcdef" };StringLengthComparator comparator = new StringLengthComparator();Arrays.sort(strArray, comparator);System.out.println(Arrays.toString(strArray));// Output: [abc, 12345, abcdef]/** 解释:`StringLengthComparator`类实现了`Comparator`接口* 并重写了`compare()`方法,以便根据字符串的长度进行比较。* `Arrays.sort()`方法用于根据* 自定义比较器对字符串数组进行排序。* https://blog.csdn.net/weixin_43359009?spm=1011.2266.3001.5343*/Arrays.sort(strArray, new Comparator<String>() {@Overridepublic int compare(String s1, String s2) {return -(s1.length() - s2.length());}});System.out.println(Arrays.toString(strArray));// Output: [abcdef, 12345, abc]/** 解释:`Arrays.sort()`方法用于根据自定义比较器对字符串数组进行排序。* 在这种情况下,比较器是一个匿名类,它重写了`compare()`方法以便根据字符串的长度进行比较。* 返回负值,可以实现降序排序。*/}

2. 使用自定义比较器对集合进行排序

2.1 实现Comparable接口

要自定义集合的排序规则,首先需要使集合中的元素类实现Comparable接口。该接口只有一个方法:

int compareTo(T o);

该方法用于比较当前对象和另一个对象的相对大小,并返回一个整数:

  • 如果当前对象小于另一个对象,则返回-1。
  • 如果当前对象等于另一个对象,则返回0。
  • 如果当前对象大于另一个对象,则返回1。

例如,要按照学生的分数对学生对象进行排序,可以定义如下学生类:

class Student implements Comparable<Student> {private String name;private int score;public Student(String name, int score) {this.name = name;this.score = score;}@Overridepublic int compareTo(Student other) {return this.score - other.score;}
}

2.2 使用Collections.sort()方法

有了实现了Comparable接口的元素类之后,就可以使用Collections.sort()方法对集合进行排序。该方法的重载版本接受一个集合作为参数:

Collections.sort(collection);

例如,要按照学生的成绩对学生集合studentList进行排序,可以使用如下代码:

List<Student> studentList = new ArrayList<>();
studentList.add(new Student("Alice", 90));
studentList.add(new Student("Bob", 80));
studentList.add(new Student("Charlie", 70));
Collections.sort(studentList);

2.3 使用Lambda表达式

在Java 8及更高版本中,可以使用Lambda表达式来代替匿名内部类,使代码更加简洁。例如,要按照学生的成绩对学生集合studentList进行排序,可以使用如下代码:

studentList.sort((s1, s2) -> s1.getScore() - s2.getScore());

2.4 代码结果

class Student implements Comparable<Student> {public String name;public int score;public Student(String name, int score) {this.name = name;this.score = score;}@Overridepublic int compareTo(Student other) {return this.score - other.score;}}public static void compareObjects() {List<Student> studentList = new ArrayList<>();studentList.add(new Student("Alice", 90));studentList.add(new Student("Bob", 80));studentList.add(new Student("Charlie", 70));Collections.sort(studentList);for (Student student : studentList) {System.out.println(student.name + ": " + student.score);}// Output:// Charlie: 70// Bob: 80// Alice: 90/** 解释:`Student`类实现了`Comparable`接口并重写了`compareTo()`方法,* 以便根据学生的分数进行比较。`Collections.sort()`方法用于根据`compareTo()`方法定义的自然顺序对学生数组进行排序。* https://blog.csdn.net/weixin_43359009?spm=1011.2266.3001.5343*/}

比较器的排序规则

在 Java 中,无论是实现 Comparable 接口的 compareTo 方法,还是创建 Comparator 接口的实例时实现的 compare 方法,其返回值都遵循一个通用的规则,以决定排序的顺序。

返回值规则

  • 负整数: 如果方法返回负整数,表示第一个参数(compareTo 中的 thiscompare 中的 o1)应该排在第二个参数(compareTo 中的 ocompare 中的 o2)之前。
  • 零: 如果方法返回零,表示这两个参数在排序时被视为相等。
  • 正整数: 如果方法返回正整数,表示第一个参数应该排在第二个参数之后。

举例

其实上文中的代码已经有过示例了,但是这里仍给出一个简单的示例并解释。

假设有一个 Person 类,其中包含 agename 两个字段,想要根据 agePerson 对象进行排序。

public class Person {int age;String name;// ...... https://blog.csdn.net/weixin_43359009?spm=1011.2266.3001.5343
}Comparator<Person> byAge = new Comparator<Person>() {@Overridepublic int compare(Person o1, Person o2) {return o1.age - o2.age;}
};

在这个比较器中,如果 o1 的年龄小于 o2 的年龄,o1.age - o2.age 将返回一个负值,表示 o1 应该排在 o2 之前,从而实现了升序排序。
反之,如果 o1 的年龄大于 o2 的年龄,将返回一个正值,表示 o1 应该排在 o2 之后。
如果两者年龄相同,返回零,表示两者在排序时被视为相等。

注意点

  • 当实现 ComparatorComparable 时,返回值不必严格限制为-1、0 或 1。任何负整数值都表示“小于”,任何正整数值都表示“大于”。
  • 在实现比较逻辑时,特别是涉及到数值差异计算的场景(如上述例子中的 o1.age - o2.age),要注意数值溢出的问题。对于大整数的比较,推荐使用 Integer.compare(x, y)Long.compare(x, y) 等静态方法,这些方法内部已经处理了溢出问题。

比较两个接口

ComparableComparator 都是 Java 中用来实现对象排序的接口,它们在用法和设计目的上有一些关键的不同之处:

Comparable 接口

  • 包路径: java.lang.Comparable
  • 用途: 当我们想要定义一个类的自然排序时使用。例如,一个 Person 类可能按照年龄或姓名自然排序。
  • 方法: 该接口只包含一个方法 compareTo(T o),任何实现了 Comparable 接口的类都必须实现这个方法。
  • 实现方式: 类内部比较机制,即一个对象自己知道如何与另一个对象进行比较。
  • 使用场景: 适用于你拥有源代码的类,并且你希望该类的对象有一个默认的排序方式。

Comparator 接口

  • 包路径: java.util.Comparator
  • 用途: 当我们需要定义多种排序方式,或者我们无法修改要排序的类的源代码时使用。例如,如果 Person 类是一个第三方库的一部分,我们无法为其实现 Comparable 接口,但我们仍然想要根据年龄或姓名对 Person 对象进行排序。
  • 方法: 该接口包含一个方法 compare(T o1, T o2),用于比较两个对象。
  • 实现方式: 类外部比较机制,即我们创建一个单独的比较器(Comparator)来定义两个对象如何比较。
  • 使用场景: 当你需要对某个类的对象进行排序,但是你不能修改原始类,或者你需要对同一个类的对象以不同的方式进行排序时。

总结

  • 修改源代码: 如果可以修改类的源代码,并且该类有一个自然的排序顺序,使用 Comparable
  • 多种排序方式或无法修改源代码: 如果你需要多种排序方式,或者你无法修改要排序的类,使用 Comparator

使用 ComparableComparator 可以让你的对象支持排序操作,如使用 Collections.sort()Arrays.sort() 方法进行排序。选择哪一个取决于你的具体需求和上述提到的考量。

比较两个方法

Arrays.sort()Collections.sort() 都是 Java 中用于排序的常用方法,但它们之间存在一些关键的区别,主要体现在它们的使用场景和内部工作机制上。

Arrays.Sort ()

  • 定义位置: java.util.Arrays 类中。
  • 使用场景: 用于对数组进行排序。可以对原始数据类型数组(如 int[], double[] 等)和对象数组(如 String[], Integer[] 等)进行排序。
  • 工作原理: Arrays.sort() 方法根据数组的数据类型采用不同的排序算法。对于原始数据类型数组,通常采用快速排序算法;而对于对象数组,则使用改进的归并排序(TimSort)。
  • 重载版本: 提供了多个重载方法,允许你对整个数组或指定范围内的元素进行排序。也可以接受一个 Comparator,用于对象数组的定制排序。

Collections.Sort ()

  • 定义位置: java.util.Collections 类中。
  • 使用场景: 专门用于对实现了 List 接口的集合进行排序,比如 ArrayList, LinkedList 等。
  • 工作原理: Collections.sort() 内部也是使用改进的归并排序算法(TimSort)来对列表进行排序。
  • 重载版本: 提供了两种形式的 sort 方法。一种是只接受 List 对象,按照元素的自然顺序进行排序;另一种是除了 List 对象外,还接受一个 Comparator 参数,用于定制排序规则。

关键区别

  • 应用类型: Arrays.sort() 用于数组,而 Collections.sort() 用于 List 接口的集合。
  • 排序算法: 对于原始类型数组,Arrays.sort() 可能使用快速排序;对于对象类型数组和 Collections.sort(),则使用 TimSort 算法。
  • 灵活性: Collections.sort() 只能用于 List 集合,而 Arrays.sort() 可以对任何类型的数组进行排序,包括原始数据类型和对象数组。
  • 定制排序: 两者都支持定制排序,允许通过传递 Comparator 实现特定的排序逻辑。

在选择使用 Arrays.sort() 还是 Collections.sort() 时,主要考虑要排序的数据类型(数组还是 List 集合)。对于集合框架中的列表,推荐使用 Collections.sort()。对于数组类型的数据,则必须使用 Arrays.sort()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/5990.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2.Neo4j的搭建启动

Graph Database 图数据库 版本对应关系 官网都是高版本&#xff0c;推荐使用下载地址可以找到社区老版本&#xff1a; https://we-yun.com/doc/neo4j/ neo4j.bat 启动脚本 cypher-shell.bat 执行CQL语句的。 import文件夹可以放入excel,csv等数据文件&#xff0c;导入到…

llamaindex 中GPTVectorStoreIndex 和 VectorStoreIndex区别

在 llama_index 库中,GPTVectorStoreIndex 和 VectorStoreIndex 都是用于创建向量存储索引的类,但它们在某些方面有所不同。 底层模型: GPTVectorStoreIndex 使用 GPT (Generative Pre-trained Transformer) 模型来生成文本的向量表示。它利用 GPT 模型的上下文理解能力来捕获…

多模态大语言模型和 Apple 的 MM1

原文地址&#xff1a;multimodal-large-language-models-apples-mm1 2024 年 4 月 13 日 抽象是计算机科学中最关键的概念之一&#xff0c;具有一些最强大的影响。从简单的角度来看&#xff0c;抽象就是将某一事物应用于多种不同情况的能力。例如&#xff0c;如果你创造了一种…

本地大语言模型LLM的高效运行专家 | Ollama

Ollama简介 Ollama是一个开源的大型语言模型服务工具&#xff0c;它帮助用户快速在本地运行大模型。通过简单的安装指令&#xff0c;用户可以执行一条命令就在本地运行开源大型语言模型&#xff0c;如Llama 2。Ollama极大地简化了在Docker容器内部署和管理LLM的过程&#xff0…

JAVA面试专题-微服务篇

Spring cloud Spring Cloud 5大组件有哪些 注册中心/配置中心&#xff1a;nacos 负载均衡&#xff1a;Ribbon 服务远程调用&#xff1a;Feign 服务保护&#xff1a;sentinel 服务网关&#xff1a;Gateway 微服务注册和发现 nacos和eureka的区别 负载均衡 微服务向Ribbon发送…

基于Spring Boot的校园疫情防控系统设计与实现

基于Spring Boot的校园疫情防控系统设计与实现 开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/idea 系统部分展示 管理员登录首页界面图&#xff0c;管理员进入校园疫…

Android --- 消息机制与异步任务

在Android中&#xff0c;只有在UIThread(主线程)中才能直接更新界面&#xff0c; 在Android中&#xff0c;长时间的工作联网都需要在workThread(分线程)中执行 在分线程中获取服务器数据后&#xff0c;需要立即到主线程中去更新UI来显示数据&#xff0c; 所以&#xff0c;如…

手撕spring框架(2)

相关系列 java中spring底层核心原理解析&#xff08;1&#xff09;-CSDN博客 java中spring底层核心原理解析(2)-CSDN博客 手撕spring框架&#xff08;1&#xff09;-CSDN博客 手撕spring框架&#xff08;3&#xff09;-CSDN博客 手撕spring框架&#xff08;4&#xff09;-CSDN博…

用龙梦迷你电脑福珑2.0做web服务器

用龙梦迷你电脑福珑2.0上做web服务器是可行的。已将一个网站源码放到该电脑&#xff0c;在局域网里可以访问网站网页。另外通过在同一局域网内的一台windows10电脑上安装花生壳软件&#xff0c;也可以在外网访问该内网服务器网站网页。该电脑的操作系统属于LAMP。在该电脑上安装…

Qt Creator导入第三方so库和jar包——Qt For Android

前言 之前了解了在Android Studio下导入so库和jar包&#xff0c;现在实现如何在Qt上导入so库和jar包。 实现 下面是我安卓开发&#xff08;需调用安卓接口的代码&#xff09;的目录&#xff08;图1&#xff09;&#xff0c;此目录结构和原生态环境&#xff08;Android Studi…

详细分析Java中的脱敏注解(附Demo)

目录 前言1. 基本知识2. 核心逻辑3. Demo4. 模版 前言 对于隐私信息&#xff0c;需要做特殊处理&#xff0c;比如身份证或者手机号等 对于Java的相关知识推荐阅读&#xff1a;java框架 零基础从入门到精通的学习路线 附开源项目面经等&#xff08;超全&#xff09; 1. 基本知…

软件定义汽车落地的五大关键要素

1、架构升级 1.1 软件架构&#xff1a;分层解耦、服务化、API 接口标准化 随着企业向软件定义汽车开发方法的转变&#xff0c;软件架构也需要同步进行升级&#xff0c;引入面向服务的架构&#xff08;Service-Oriented Architecture&#xff0c;简称 SOA&#xff09;方法论。…

LeetCode刷题之买卖股票的最佳时机

文章目录 1. 买卖股票的最佳时机1.1 描述1.2 分析1.3 解答 2.买卖股票的最佳时机II2.1 描述2.2 分析2.3 解答2.4 拓展2.5 拓展二 1. 买卖股票的最佳时机 题121 买卖股票的最佳时机 1.1 描述 给定一个数组 prices &#xff0c;它的第 i 个元素 prices[i] 表示一支给定股票第 …

【Android学习】按钮监听代码

1. 简介 Button组件是Android中常用的组件&#xff0c;Button常需要和View.OnClickListener配合使用。这里记录下Button配置监听的过程。 2. 代码分析 2.1 Layout的XML代码 <Buttonandroid:id"id/btn"android:layout_width"match_parent"android:lay…

ThreeJS:响应式画布与全屏控制

响应式画布 响应式画布&#xff1a;在用户缩放浏览器窗口时&#xff0c;为便于动态更新画布尺寸与宽高比例&#xff0c;需要通过监听resize事件&#xff0c;来实现响应式画布。 window.onresize function () {//TODO:重置渲染器宽高比renderer.setSize(window.innerWidth, wi…

图文、视频处理等自媒体工具

文章目录 文本转文本图片canva同类竞品文本生成PDF,PDF再导出为图片贴入笔记类应用(如小米笔记App)中然后选择以图片形式分享UU在线工具的文字生成长图醒图App其他竞品文本转配音视频剪映将文本生成一段朗读该文本的配音视频(需要自行切割多段内容并分配时间轴)腾讯智影将…

为人处事电影解说,全新升级瀚海跑道一分钟一条视频,全平台可推广,轻轻松松日入1000

自古以来&#xff0c;我国流行的一种现象是&#xff0c;大多数人都会与领导或上司打交道。由于某些话题不宜公开讨论&#xff0c;因此出现了许多含蓄的表达方式。随着年龄的增长&#xff0c;人们的态度也发生了变化&#xff0c;从最初的轻视到现在的重视。 下 载 地 址&#…

VG做mirror引起的块偏移

事件起因 Oracle10.2环境 Aix操作系统使用aix的lvm技术。制作vg的mirror。以此来替换掉老的存储。 做mirror前&#xff0c;数据库已完全关闭 故障现象 在启动数据库时&#xff0c;发现IO错误。该系统的spfile&#xff0c;ctl&#xff0c;dbf均是用lv做的裸设备。其中dbf是使…

WebGL是啥

WebGL&#xff08;全写为Web Graphics Library&#xff09;是一种3D绘图协议&#xff0c;这种绘图技术标准允许把JavaScript和OpenGL ES 2.0结合在一起&#xff0c;通过增加OpenGL ES 2.0的一个JavaScript绑定&#xff0c;WebGL可以为HTML5 Canvas提供硬件3D加速渲染。这样&…

【重学C语言】十二、指针高级-函数指针

【重学C语言】十二、指针高级-函数指针 函数指针小案例回调函数如何看懂复杂的指针右左法则案例走起1.int (\*p[5])(int\*)2. int (\*fun)(int \*p,int (\*pf)(int \*))3. int (\*(\*fun)[5])(int \*p)4. int (\*(\*fun)(int \*p))[5]5. int(\*(\*fun())())()函数指针 函数指针…