当前位置: 首页 > news >正文

JAVA中关于compareTo方法的原理深挖

一、compareTo()方法

在深挖compareTo方法前,首先我们需要了解compareTo方法的来龙去脉。compareTo方法的目的是用来比较两个对象的大小的。假如有两个对象a1,a2。包含姓名,年龄,身高三个属性,现在要求根据年龄或者性别进行排序。这就要用到compareTo方法。

二、如何使用compareTo方法

要想使用compareTo方法对对象进行排序,首先要使得该对象类实现comparable接口,并重写compareTo方法,重写compareTo方法时要制定比较规则。

package com.njau.d6_map_impl;import java.util.Objects;public class Student implements Comparable<Student>{private String name;private int age;private double height;public Student(String name, int age, double height) {this.name = name;this.age = age;this.height = height;}@Overridepublic int compareTo(Student o) {return this.age-o.age;}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Student student = (Student) o;return age == student.age && Double.compare(height, student.height) == 0 && Objects.equals(name, student.name);}@Overridepublic int hashCode() {return Objects.hash(name, age, height);   // 没有重写hashCode之前,不同对象不一样。重写后根据属性计算hash值,属性相同的被认为是同一对象,hash值一样。属性是否一样通过重写的equals方法判断}public Student() {}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public double getHeight() {return height;}public void setHeight(double height) {this.height = height;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +", height=" + height +'}';}
}

三、如何指定比较规则

那么该如何指定比较规则呢?这里主要针对int类型数据比较,double类型数据比较以及字符串类型数据比较三种来讲解比较规则:

1.int类型数据比较

int类型的数据指定比较规则最为简单,在重写compareTo方法时,this代表主调对象(主动比较对象),而o代表从调对象(被动比较对象)。Java会默认左边对象是主调对象(this对象),右边对象是从调对象(o对象),这个默认规则是不会改变的。

而比较规则是:当左边对象>右边对象的值时,compareTo方法会返回一个正整数。Java便认为是this对象>o对象(因为Java会默认左边对象就是this,右边对象就是o)。Java排序o,this。

当左边对象<右边对象的值时,compareTo方法会返回一个负整数。Java便认为是this对象<o对象(因为Java会默认左边对象就是this,右边对象就是o)。Java排序this,o。

当左边对象=右边对象的值时,compareTo方法会返回一个负整数。Java便认为是this对象=o对象(因为Java会默认左边对象就是this,右边对象就是o)。

举例说明

package com.njau.d6_map_impl;import java.util.Objects;public class Student implements Comparable<Student>{private String name;private int age;private double height;public Student(String name, int age, double height) {this.name = name;this.age = age;this.height = height;}@Overridepublic int compareTo(Student o) {return this.age-o.age;}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Student student = (Student) o;return age == student.age && Double.compare(height, student.height) == 0 && Objects.equals(name, student.name);}@Overridepublic int hashCode() {return Objects.hash(name, age, height);   // 没有重写hashCode之前,不同对象不一样。重写后根据属性计算hash值,属性相同的被认为是同一对象,hash值一样。属性是否一样通过重写的equals方法判断}public Student() {}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public double getHeight() {return height;}public void setHeight(double height) {this.height = height;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +", height=" + height +'}';}
}

假设this.age>o.age

this.age-o.age。左边this右边o,>0则Java则认为左边对象this>右边对象o,则排序为o,this。升序排序。实际上也是升序排序。 

如果想要降序排序,那么则改为o.age-this.age。左边o右边this,<0则Java则认为左边对象this<右边对象o,则排序为this,o。Java认为是升序排序。实际上是降序排序。

2.double类型数据比较

double类型的数据比较,会出现精度问题,因此不能直接相减。为了解决精度问题,Java中的Double.compare方法派上用场。Double.compare(double1,double2),如果double1>double2,则返回正整数。如果double1<double2,则返回负整数。如果double1=double2,则返回0。这样的话,就符合了Java的比较规则。

return Double.compare(o1.getHeight(),o2.getHeight());

3.字符串类型的数据比较

return this.name.compareTo(o.name);

字符串类型的属性进行比较时,会将字符串转换成字符数组,再通过字符数组进行比较,排序时按照字符的Unicode编码进行排序。首先Java虚拟机会将主调字符串(由编译时生成,也叫做value[])赋给String类中定义的value[]字符数组(使用final定义,只能初始化一次)。

public final class String implements java.io.Serializable, Comparable<String>, CharSequence {// The value is used for character storage.private final char value[];// Other fields and methods...// Constructor to initialize string from character arraypublic String(char value[]) {this.value = Arrays.copyOf(value, value.length);}// Other constructors and methods...
}

紧接着会执行String类中的compareTo方法,将从调字符串进行传入并比较

public int compareTo(String anotherString) {int len1 = this.length();int len2 = anotherString.length();int lim = Math.min(len1, len2);char v1[] = this.value;char v2[] = anotherString.value;int k = 0;while (k < lim) {char c1 = v1[k];char c2 = v2[k];if (c1 != c2) {return c1 - c2;}k++;}return len1 - len2;
}

this:主调字符串

anotherString:从调字符串(在编译阶段会被转换成字符数组)

原理:

获取字符串长度: 

int len1 = this.length();
int len2 = anotherString.length();

length() 方法返回字符串的长度 

将字符串转换为字符数组:

char v1[] = this.toCharArray();
char v2[] = anotherString.toCharArray();

toCharArray() 方法将字符串转换为字符数组。

逐字符比较:

int k = 0;
while (k < lim) {char c1 = v1[k];char c2 = v2[k];if (c1 != c2) {return c1 - c2;}k++;
}

逐字符比较两个字符串,返回第一个不同字符的差值。 

长度比较: 

return len1 - len2;

如果所有字符都相同,则返回字符串长度的差值。

最终会根据Unicode编码比较出字符串的前后顺序。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 【论文阅读】AsyncDiff: Parallelizing Diffusion Models by Asynchronous Denoising
  • VS2019 因公司加密无法运行程序原因
  • 树莓派4B_OpenCv学习笔记21:OpenCV_haar人脸识别
  • Day1--每日一练
  • P8086 『JROI-5』Music
  • 深入理解外观模式(Facade Pattern)及其实际应用
  • 网络钓鱼中的高级同形异义:网络安全的新威胁
  • 【前端】css控制背景图片缩放
  • C++list的模拟实现
  • 【Python123题库】#统计单词的数量 #各位数字之和为5的数 #输出单词
  • qt 按钮链接一个槽函数
  • 昇思25天学习打卡营第十六天|基于MindSpore的GPT2文本摘要
  • 操作系统---进程的同步和互斥(易错知识点梳理)
  • 银行小额支付系统的全面解析
  • jQuery Mobile 实例:构建响应式移动网页的实践指南
  • __proto__ 和 prototype的关系
  • 【JavaScript】通过闭包创建具有私有属性的实例对象
  • 4个实用的微服务测试策略
  • Javascripit类型转换比较那点事儿,双等号(==)
  • Java-详解HashMap
  • Mac 鼠须管 Rime 输入法 安装五笔输入法 教程
  • Unix命令
  • Yeoman_Bower_Grunt
  • 七牛云 DV OV EV SSL 证书上线,限时折扣低至 6.75 折!
  • 巧用 TypeScript (一)
  • 使用Gradle第一次构建Java程序
  • 线上 python http server profile 实践
  • 一个JAVA程序员成长之路分享
  • 3月27日云栖精选夜读 | 从 “城市大脑”实践,瞭望未来城市源起 ...
  • ​LeetCode解法汇总307. 区域和检索 - 数组可修改
  • #pragma once与条件编译
  • (DenseNet)Densely Connected Convolutional Networks--Gao Huang
  • (floyd+补集) poj 3275
  • (Python) SOAP Web Service (HTTP POST)
  • (附源码)springboot太原学院贫困生申请管理系统 毕业设计 101517
  • (教学思路 C#之类三)方法参数类型(ref、out、parmas)
  • (三)终结任务
  • (十八)devops持续集成开发——使用docker安装部署jenkins流水线服务
  • (未解决)macOS matplotlib 中文是方框
  • (一)Dubbo快速入门、介绍、使用
  • (原创)可支持最大高度的NestedScrollView
  • (转)Oracle存储过程编写经验和优化措施
  • (状压dp)uva 10817 Headmaster's Headache
  • * 论文笔记 【Wide Deep Learning for Recommender Systems】
  • . ./ bash dash source 这五种执行shell脚本方式 区别
  • .MyFile@waifu.club.wis.mkp勒索病毒数据怎么处理|数据解密恢复
  • .NET 8.0 中有哪些新的变化?
  • .NET Core SkiaSharp 替代 System.Drawing.Common 的一些用法
  • .NET 设计一套高性能的弱事件机制
  • .NET中分布式服务
  • /dev/sda2 is mounted; will not make a filesystem here!
  • /usr/lib/mysql/plugin权限_给数据库增加密码策略遇到的权限问题
  • @Autowired自动装配
  • @html.ActionLink的几种参数格式
  • @requestBody写与不写的情况