在Java中,凡是涉及到比较的,可以分为两类情况:一类是基本数据类型的比较,另一类是引用数据类型的比较。对于基本数据类型的比较,我们通过关系运算符(==、>、<、!=、>=、<=)进行它们之间的比较,而对于引用数据类型,并不能简单的通过关系运算符来进行它们的比较,因为引用数据类型如果使用关系运算符比较的话,比较的是它们的引用类型,并不是对象的内容。

本文就引用数据类型如何进行比较展开讨论。

1.对象比较存在的问题

来看下面的例子:

class Card {public int rank;  //点数public String suit;  //花色public Card(int rank, String suit) {this.rank = rank;this.suit = suit;}
}public class Test {public static void main(String[] args) {Card card1 = new Card(1,"方块");Card card2 = new Card(2,"方块");Card card3 = card1;System.out.println(card1 > card2);   //1.System.out.println(card1 == card2);  //2.System.out.println(card2 < card1);   //3.System.out.println(card1 == card3);  //4.}
}

对于代码中的1.、2.、3.和4.语句,1.和3.不能通过编译,2.和4.可以通过遍历,并且运行结果分别是:false(因为card1和card2是不同的对象)、true(card1和card3是相同的对象)。

面对这个结果,我们易产生疑问:为什么Java中引用类型的变量不能直接按照<或者>进行比较,为什么==就可以呢

这是因为:对于我们用户实现的自定义类型,都默认继承Object类,而Object类中提供了equals方法,而==默认情况下调用equals方法,但是该方法的比较规则并没有比较引用变量引用对象的内容,而是直接比较引用变量的地址

但是有些情况下,我们需要比较的是引用变量引用对象的内容,比如:向优先级队列中插入某个对象时,需要比较对象的内容来进行调整堆,那这又该怎么办呢?

2.对象比较的方式

对于上述所说的需要比较对象内容的情况,再根据具体的比较需要,有三种方案,它们分别是:

重写父类的equals方法实现Comparable接口使用比较器Comparator接口

2.1 重写父类的equals方法

该方案的核心用途:判断两个对象的内容是否 “逻辑相等”,是最基础的对象内容比较方式。

适用场景:一般的对象内容比较(如判断两个Person是否为同一个人)

在上述的例子中,我们我们认为两张牌的点数和花色一样,就认为它们是同一张牌,那么重写equals方法,再进行测试:

package demo1;import java.util.Objects;class Card {public int rank;  //点数public String suit;  //花色public Card(int rank, String suit) {this.rank = rank;this.suit = suit;}@Overridepublic boolean equals(Object o) {//自己和自己比较if (this == o) {return true;}//如果是null对象或者o不是不是Card的子类if (o == null || getClass() != o.getClass()) {return false;}Card card = (Card) o;//比较点数和花色(花色是String类型,因此调用String的equals方法进行比较)return rank == card.rank && Objects.equals(suit, card.suit);}}public class Test {public static void main(String[] args) {Card card1 = new Card(1,"方块");Card card2 = new Card(1,"方块");Card card3 = card1;System.out.println(card1.equals(card2));System.out.println(card1.equals(card3));}
}//运行结果
true
true

代码解读:

  1. 如果指向同一个对象,返回 true
  2. 如果传入的为 null,返回 false
  3. 如果传入的对象类型不是 Card,返回 false
  4. 按照类的实现目标完成比较,例如这里只要花色和数值一样,就认为是相同的牌
  5. 注意下调用其他引用类型的比较也需要 equals,例如这里的 suit 的比较

注意:重写父类equal的方式虽然可以比较,但缺陷是:equal只能按照相等进行比较,不能按照大于、小于的方式进行比较,也就是说只能比较两个东西是不是同一个。

2.2 实现Comparable接口

该方案的核心用途:为类定义 “默认排序规则”,让对象自身具备可比较性。

适用场景:对象有明确的 “自然顺序”(如学生按学号排序、商品按价格排序),且排序规则相对固定。

Comparable是JDK提供的泛型的比较接口类,它的源码如下:

public interface Comparable<E> {

        // 返回值:

        // < 0: 表示 this 指向的对象小于 o 指向的对象

         // == 0: 表示 this 指向的对象等于 o 指向的对象

         // > 0: 表示 this 指向的对象大于 o 指向的对象

}

对于我们用户自定义类型,如果想要按照大小进行比较时:在定义类时,实现Comparable接口即可,然后在类中重写CompareTo方法。像这样:

class Card implements Comparable<Card>{public int rank;  //点数public String suit;  //花色public Card(int rank, String suit) {this.rank = rank;this.suit = suit;}//不在意花色,进行点数的比较@Overridepublic int compareTo(Card o) {if (o == null) {return 1;}return rank - o.rank;}
}
public class Test {public static void main(String[] args) {Card card1 = new Card(2,"梅花");Card card2 = new Card(3,"方块");Card card3 = new Card(2,"方块");System.out.println(card1.compareTo(card2));  // < 0,说明card1小于card2System.out.println(card1.compareTo(card3));  //== 0,说明card1等于card3System.out.println(card2.compareTo(card3));  // > 0,说明card2大于card3}
}//运行结果
-1
0
1

【注意】Comparable是Java.lang中的接口类,可以直接使用。

2.3 使用比较器Comparator接口

该方案的核心用途:为类定义 “临时 / 额外的排序规则”,不修改原类代码。

适用场景

  • 需要多种排序规则(如Person既可以按年龄排,也可以按姓名排);
  • 无法修改原类代码(如第三方库的类);
  • 优先级队列(PriorityQueue)的元素排序(建大根堆需要)。

按照比较器方式进行比较,具体的操作如下:

1.用户自定义比较器类,实现Comparator接口

public interface Comparator {

        // 返回值:

        // < 0: 表示 o1 指向的对象小于 o2 指向的对象

        // == 0: 表示 o1 指向的对象等于 o2 指向的对象

        // > 0: 表示 o1 指向的对象等于 o2 指向的对象

        int compare(T o1, T o2);

}

2.重写Comparator中的compare方法

举个例子:

import java.util.Comparator;class Card {public int rank;  //点数public String suit;  //花色public Card(int rank, String suit) {this.rank = rank;this.suit = suit;}
}//自定义比较器类
class CardComparator implements Comparator<Card> {//重写compare方法//依旧按照数值比较@Overridepublic int compare(Card o1, Card o2) {//如果两张牌数值一样if (o1.rank == o2.rank) {return 0;}//如果第一种牌为nullif (o1 == null) {return -1;}//如果第二张牌为nullif (o2 == null) {return 1;}//正常情况return o1.rank - o2.rank;}
}
public class Test {public static void main(String[] args) {Card card1 = new Card(1,"方块");Card card2 = new Card(2,"方块");Card card3 = new Card(1,"方块");//定义比较器对象CardComparator cardComparator = new CardComparator();System.out.println(cardComparator.compare(card1,card3)); // == 0,说明两张牌相等System.out.println(cardComparator.compare(card1,card2)); // < 0,说明card1小于card2System.out.println(cardComparator.compare(card2,card1)); // > 0,说明card2大于card1}
}//运行结果
0
-1
1

【注意】Comparator是java.util 包中的泛型接口类,使用时必须导入对应的包。

2.4 三种方式的对比

重写的方法说明
Object.equals因为所有类都是继承自 Object 的,所以直接覆写即可,不过只能比较相等与 否
Comparable.compareTo

需要手动实现接口,侵入性比较强,但一旦实现,每次用该类都有顺序,属于内部顺序

Comparator.compare需要实现一个比较器对象,对待比较类的侵入性弱,但对算法代码实现侵入性 强

到此,关于如何去比较引用数据类型变量这个问题已经得到解决,我们有三种方案,按需使用即可!感谢您的阅读,如有错误,还请指出!谢谢!

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

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

相关文章

企智汇建筑施工项目管理系统:全周期数字化管控,赋能工程企业降本增效!​建筑工程项目管理软件!建筑工程项目管理系统!建筑项目管理软件企智汇软件

在建筑施工行业&#xff0c;项目进度滞后、成本超支、质量安全隐患频发、多方协同不畅等问题&#xff0c;一直是制约企业发展的痛点。传统依赖人工记录、Excel 统计的管理模式&#xff0c;不仅效率低下&#xff0c;更易因信息断层导致决策失误。企智汇建筑施工项目管理系统凭借…

k8s-临时容器学习

临时容器学习1. 什么是临时容器2. 实验1. 什么是临时容器 在官网&#xff1a;https://kubernetes.io/zh-cn/docs/concepts/workloads/pods/ephemeral-containers/ 中有介绍 临时容器是用于调试Pod中崩溃的容器或者不具备调试工具&#xff0c;比如在一个运行着业务的容器中&am…

Python 2025:低代码开发与自动化运维的新纪元

从智能运维到无代码应用&#xff0c;Python正在重新定义企业级应用开发范式在2025年的企业技术栈中&#xff0c;Python已经从一个"开发工具"演变为业务自动化的核心平台。根据Gartner 2025年度报告&#xff0c;68%的企业在自动化项目中使用Python作为主要开发语言&am…

Netty 在 API 网关中的应用篇(请求转发、限流、路由、负载均衡)

Netty 在 API 网关中的应用篇&#xff08;请求转发、限流、路由、负载均衡&#xff09;随着微服务架构的普及&#xff0c;API 网关成为服务之间通信和安全控制的核心组件。在构建高性能网关时&#xff0c;Netty 因其高吞吐、低延迟和异步非阻塞 IO 的特性&#xff0c;成为不少开…

基于STM32设计的青少年学习监控系统(华为云IOT)_282

文章目录 一、前言 1.1 项目介绍 【1】项目开发背景 【2】设计实现的功能 【3】项目硬件模块组成 【4】设计意义 【5】国内外研究现状 【6】摘要 1.2 设计思路 1.3 系统功能总结 1.4 开发工具的选择 【1】设备端开发 【2】上位机开发 1.5 参考文献 1.6 系统框架图 1.7 系统原理…

手写Spring底层机制的实现【初始化IOC容器+依赖注入+BeanPostProcesson机制+AOP】

摘要&#xff1a;建议先看“JAVA----Spring的AOP和动态代理”这个文章&#xff0c;解释都在代码中&#xff01;一&#xff1a;提出问题依赖注入1.单例beans.xml<?xml version"1.0" encoding"UTF-8"?> <beans xmlns"http://www.springframe…

5G NR-NTN协议学习系列:NR-NTN介绍(2)

NTN网络作为依赖卫星的通信方式&#xff0c;需要面对的通信距离&#xff0c;通信双方的移动速度都和之前TN网络存在巨大差异。在距离方面相比蜂窝地面网络Terrestrial Network通信距离从最小几百米到最大几十km的情况&#xff0c;NTN非地面网络的通信距离即使是近地轨道的LEO卫…

线扫相机采集图像起始位置不正确原因总结

1、帧触发开始时间问题 问题描述: 由于帧触发决定了线扫相机的开始采集图像位置,比如正确的位置是A点开始采集,结果你从B点开始触发帧信号,这样出来的图像起始位置就不对 解决手段: 软件需要记录帧触发时轴的位置 1)控制卡控制轴 一般使用位置比较触发,我们可以通过监…

校园管理系统练习项目源码-前后端分离-【node版】

今天给大家分享一个校园管理系统&#xff0c;前后端分离项目。这是最近在练习前端编程&#xff0c;结合 node 写的一个完整的项目。 使用的技术&#xff1a; Node.js&#xff1a;版本要求16.20以上。 后端框架&#xff1a;Express框架。 数据库&#xff1a; MySQL 8.0。 Vue2&a…

【项目】 :C++ - 仿mudou库one thread one loop式并发服务器实现(模块划分)

【项目】 &#xff1a;C - 仿mudou库one thread one loop式并发服务器实现一、HTTP 服务器与 Reactor 模型1.1、HTTP 服务器概念实现步骤难点1.2、Reactor 模型概念分类1. 单 Reactor 单线程2. 单 Reactor 多线程3. 多 Reactor 多线程目标定位总结二、功能模块划分2.1、SERVER …

浴室柜市占率第一,九牧重构数智卫浴新生态

作者 | 曾响铃文 | 响铃说2025年上半年&#xff0c;家居市场在政策的推动下展现出独特的发展态势。国家出台的一系列鼓励家居消费的政策&#xff0c;如“以旧换新”国补政策带动超6000万件厨卫产品焕新&#xff0c;以及我国超2.7亿套房龄超20年的住宅进入改造周期&#xff0c;都…

源码分析之Leaflet中TileLayer

概述 TileLayer 是 Layer 的子类&#xff0c;继承自GridLayer基类&#xff0c;用于加载和显示瓦片地图。它提供了加载和显示瓦片地图的功能&#xff0c;支持自定义瓦片的 URL 格式和参数。 源码分析 源码实现 TileLayer的源码实现如下&#xff1a; export var TileLayer GridL…

php学习(第二天)

一.网站基本概念-服务器 1.什么是服务器? 1.1定义 服务器&#xff08;server&#xff09;,也称伺服器&#xff0c;是提供计算服务的设备。 供计算服务的设备” 这里的“设备”不仅指物理机器&#xff08;如一台配有 CPU、内存、硬盘的计算机&#xff09;&#xff0c;也可以指…

C++(友元和运算符重载)

目录 友元&#xff1a; 友元函数&#xff1a; 示例&#xff1a; 友元类&#xff1a; 示例&#xff1a; 优点&#xff1a; 注意事项&#xff1a; 运算符重载&#xff1a; 注意&#xff1a; 示例&#xff1a; 友元&#xff1a; C中如果想要外部函数或者类对一个类的pr…

和平精英风格射击游戏开发指南

本教程将完整讲解如何开发一款和平精英风格的HTML射击游戏&#xff0c;涵盖核心设计理念、代码架构与关键实现细节。 核心设计架构 游戏机制系统 角色控制系统&#xff1a;通过键盘实现玩家移动战斗系统&#xff1a;子弹发射与碰撞检测道具系统&#xff1a;武器、弹药和医疗包收…

21.1 《24GB显存搞定LLaMA2-7B指令微调:QLoRA+Flash Attention2.0全流程实战》

24GB显存搞定LLaMA2-7B指令微调:QLoRA+Flash Attention2.0全流程实战 实战 LLaMA2-7B 指令微调 一、指令微调技术背景 指令微调(Instruction Tuning)是大模型训练中的关键技术突破点。与传统全量微调(Full Fine-Tuning)相比,指令微调通过特定格式的指令-响应数据训练,…

周志华《机器学习导论》第10章 降维与度量学习

https://www.lamda.nju.edu.cn/aml24fall/slides/Chap10.pptx 目录 1.MDS (Multiple Dimensional Scaling) 多维缩放方法 2. 主成分分析 (Principal Component Analysis, PCA) 2.1 凸优化证明 2.2 人脸识别降维应用 3. 核化PCA 4. 流行学习 4.1 LLE 局部线性嵌入&#…

Kubernetes 弹性伸缩:深入讲解 HPA 和 VPA

1. 介绍 Kubernetes 提供了多种资源管理方式&#xff0c;其中 弹性伸缩&#xff08;Auto-scaling&#xff09;是最重要的特性之一。弹性伸缩可以根据应用的负载变化自动调整 Pod 的数量和资源&#xff0c;以确保在高负载下应用能够正常运行&#xff0c;而在低负载时节省资源。在…

大数据毕业设计选题推荐-基于大数据的家庭能源消耗数据分析与可视化系统-Hadoop-Spark-数据可视化-BigData

✨作者主页&#xff1a;IT毕设梦工厂✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、PHP、.NET、Node.js、GO、微信小程序、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇…

【Spring】原理解析:Spring Boot 自动配置的核心机制与实战剖析

一、引言在当今的 Java 开发领域&#xff0c;Spring Boot 凭借其快速搭建项目、简化配置等优势&#xff0c;成为了众多开发者的首选框架。而 Spring Boot 自动配置作为其核心特性之一&#xff0c;极大地提升了开发效率&#xff0c;让开发者能够更专注于业务逻辑的实现。本文将深…