《Java初阶数据结构》----8.<java对象的比较总结>

目录

前言

一、Java对象的比较

1.1基本类型的比较

 1.2 对象比较的问题(==与equals)

1.3对象的比较 (三种常用方式)

1.重写equals方法

2.基于Comparble接口类的比较

3.基于比较器比较(Comparator接口)

三种方式对比

 二、集合框架中PriorityQueue的比较方式

2.1 PriorityQueue中插入对象

2.2 PriorityQueue采用的Comparble和Comparator两种方式。

三、使用PriorityQueue创建大小堆,解决TOPK问题


前言

      大家好,我目前在学习java。之前也学了一段时间,但是没有发布博客。时间过的真的很快。我会利用好这个暑假,来复习之前学过的内容,并整理好之前写过的博客进行发布。如果博客中有错误或者没有读懂的地方。热烈欢迎大家在评论区进行讨论!!!

      喜欢我文章的兄弟姐妹们可以点赞,收藏和评论我的文章。喜欢我的兄弟姐妹们以及也想复习一遍java知识的兄弟姐妹们可以关注我呦,我会持续更新滴,
     望支持!!!!! 一起加油呀!!!!

语言只是工具,不能决定你好不好找工作,决定你好不好找工作的是你的能力!!!

学历本科及以上就够用了!!!


本篇博客主要讲解Java基础语法中的、

1.java中对象的比较

基本类型的比较、对象比较的问题(==与equals)、对象的比较 (三种常用方式)

2.集合框架中PriorityQueue的比较方式采用的Comparble和Comparator两种方式。

3.使用PriorityQueue创建大小堆,解决TOPK问题

一、Java对象的比较

1.1基本类型的比较

我们知道基本类型的数据可以直接比较大小

比较整型

        int a = 10;int b = 20;System.out.println(a > b);System.out.println(a < b);System.out.println(a == b);

运行结果

false
true
false

 比较字符型

        char c1 = 'A';char c2 = 'B';System.out.println(c1 > c2);System.out.println(c1 < c2);System.out.println(c1 == c2);

运行结果

false
true
false

比较布尔型 

        boolean b1 = true;boolean b2 = false;System.out.println(b1 == b2);System.out.println(b1 != b2);

运行结果

false
true

 1.2 对象比较的问题(==与equals)

我们定义一张卡牌,第一张是红桃1的牌。第二张是红桃2牌。

第三张与第一张一样是红桃1。

class Card{public int rank;//数值public String suit;//花色public Card(int rank, String suit) {this.rank = rank;this.suit = suit;}
}
public class Main {public static void main(String[] args) {Card card1 = new Card(1,"♥");Card card2 = new Card(2,"♥");Card card3 =card1;System.out.println(card1 == card2);System.out.println(card1 == card3);}
}
//运行结果
false
true

card1和card2指向不同的对象。因此打印false。(哈希值不同)

card1和card3是指向同一个对象因此打印true(哈希值相同)

注意:我们不能使用大于号、小于号去比较。

因为Java中引用类型的变量不能直接按照 > 或者 < 方式进行比较。会编译报错。

可以使用==去比较,是因为用户实现自定义类型默认继承自Object类,而Object类中提供了equal方法,而==默认情况下调用的就是equals方法。

但是该方法的比较规则是:没有比较引用变量引用对象的内容,而是直接比较引用变量的地址(也就是哈希值)

  Object中equals的实现源码。

//可以看到:直接比较的是两个引用变量的地址 
public boolean equals(Object obj) {return (this == obj);
}

1.3对象的比较 (三种常用方式)

1.重写equals方法

有些情况下,需要比较的是对象中的内容,比如:向优先级队列中插入某个对象时,需要对按照对象中内容来调整堆,那该如何处理呢?

我们需要重写父类的equals方法。

如下代码中,我们在Card类中重写父类Object的equals方法。

this的含义。this是本类Card的类型。而谁调用了这个方法,this就是谁的引用。

我们通过

return this.rank == c.rank && this.suit.equals(c.suit);

这个来比较对象里面的内容。

注意基本类型可以直接比较,但引用类型最好调用其equal方法。如比较字符串suit我们最好使用equals。而不是==。

因为 == 用于检查两个字符串变量是否引用同一个对象。String类的equals方法用来比较字符串的内容。。

class Card{public int rank;//数值public String suit;//花色public Card(int rank, String suit) {this.rank = rank;this.suit = suit;}@Overridepublic boolean equals(Object obj) {if (this == obj){return true;}//如果obj为null或者obj不是Card的子类。返回falseif ((obj == null || !(obj instanceof Card))){return false;}Card c = (Card) obj;//this的含义。this本类Card的类型。而谁调用了这个方法,this就是谁的引用。return this.rank == c.rank && this.suit.equals(c.suit);//我们通过return这个来比较对象里面的内容。}
}
public class Main {public static void main(String[] args) {Card card1 = new Card(1,"♥");Card card2 = new Card(1,"♥");Card card3 = new Card(2,"♥");Card card4 =card1;System.out.println(card1 == card2);System.out.println(card1.equals(card2));System.out.println(card1.equals(card3));System.out.println(card1.equals(card4));}
}
//运行结果
false
true
false

 运行结果:

1.card1和card2。使用==比较。对象里面的内容虽然相同但是,引用地址不同。因此第一个是false。

2.card1和card2。使用我们重写的equals比较。对象里面的内容相同,因此返回true。

3.card1和card3。使用我们重写的equals比较。对象内容不同因此返回false

注:

一般重写 equals 就是上面演示的

1. 如果指向同一个对象,返回 true

2. 如果传入的为 null,返回 false

3. 如果传入的对象类型不是 Card,返回 false

4. 按照类的实现目标完成比较,例如这里只要花色和数值一样,就认为是相同的牌

重写基类equal的方式虽然可以比较,但缺陷是:equals只能按照相等进行比较,不能按照大于、小于的方式进行比较。

2.基于Comparble接口类的比较

Comparble是JDK提供的泛型的比较接口类,源码实现具体如下:

public interface Comparable<T> {public int compareTo(T o);
}

返回值:

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

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

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

对用用户自定义类型,如我们的Card类。如果要想按照大小与方式进行比较时:在定义类时,实现Comparble接口即可,然后在类中重写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;//>0.表示 this 指向的对象大于 o 指向的对象}return this.rank - o.rank;//>0.表示 this 指向的对象大于 o 指向的对象//=0.表示 this 指向的对象等于 o 指向的对象//<0.表示 this 指向的对象小于 o 指向的对象}
}
public class Main {public static void main(String[] args) {Card card1 = new Card(2,"♥");Card card2 = new Card(1,"♥");Card card3 = new Card(3,"♥");Card card4 = new Card(3,"♥");System.out.println(card1.compareTo(card2));System.out.println(card1.compareTo(card3));System.out.println(card3.compareTo(card4));}
}
//运行结果:
1 //表示card1更大
-1 //表示card2更大
0 //表示card3和card4一样大

注意:

1.如下代码,是泛型比较,别忘了<Card>。

class Card implements Comparable<Card>

 Compareble是java.lang中的接口类,可以直接使用。不需要导入包。

3.基于比较器比较(Comparator接口)

按照比较器方式进行比较,具体步骤如下:

1.用户自定义比较器类,实现Comparator接口。Comparator接口比较的源码如下:

public interface Comparator<T> {// 返回值:// < 0: 表示 o1 指向的对象小于 o2 指向的对象// == 0: 表示 o1 指向的对象等于 o2 指向的对象// > 0: 表示 o1 指向的对象大于 o2 指向的对象int compare(T o1, T o2);
}

2.与Comparble接口的比较方法的返回值类似。

3.重写Comparator中的compare方法

    @Overridepublic int compare(Card o1, Card o2) {if(o1 == o2){return 0;}if (o1 == null){return -1;}if(o2 == null){return 1;}return o1.rank-o2.rank;}

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

完整代码如下:

class Card{public int rank;//数值public String suit;//花色public Card(int rank, String suit) {this.rank = rank;this.suit = suit;}}
//定义一个比较器类,专门实现Card的比较
class CardComparator implements Comparator<Card> {@Overridepublic int compare(Card o1, Card o2) {if(o1 == o2){return 0;}if (o1 == null){return -1;}if(o2 == null){return 1;}return o1.rank-o2.rank;}
}
public class Main {public static void main(String[] args) {Card card1 = new Card(2,"♥");Card card2 = new Card(1,"♥");Card card3 = new Card(3,"♥");Card card4 = new Card(3,"♥");//定义比较器对象CardComparator comparator = new CardComparator();System.out.println(comparator.compare(card1,card2));System.out.println(comparator.compare(card1,card3));System.out.println(comparator.compare(card3,card4));}
}
//运行结果
1//表示card1 > card2
-1//表示card1 < card3
0//表示card3 = card4

三种方式对比

 二、集合框架中PriorityQueue的比较方式

2.1 PriorityQueue中插入对象

上一篇文章我们讲了优先级队列,优先级队列在插入元素时有个要求:插入的元素不能是null或者元素之间必须要能够进行比较,为了简单起见,我们只是插入了Integer类型,那优先级队列中能否插入自定义类型对象呢?

优先级队列底层使用堆,而向堆中插入元素时,为了满足堆的性质,必须要进行元素的比较。而如果Card没有实现比较的方法,则会抛出异常。

2.2 PriorityQueue采用的Comparble和Comparator两种方式。

集合框架中的PriorityQueue底层使用堆结构,因此其内部的元素必须要能够比大小 

PriorityQueue采用了: Comparble和Comparator两种方式。

 1. Comparble是默认的内部比较方式,如果用户插入自定义类型对象时,该类对象必须要实现Comparble接口,并覆写compareTo方法

2. 用户也可以选择使用比较器对象,如果用户插入自定义类型对象时,必须要提供一个比较器类,让该类实现 Comparator接口并覆写compare方法。

JDK中PriorityQueue的实现:

// JDK中PriorityQueue的实现:
public class PriorityQueue<E> extends AbstractQueue<E>implements java.io.Serializable {// ...// 默认容量private static final int DEFAULT_INITIAL_CAPACITY = 11;// 内部定义的比较器对象,用来接收用户实例化PriorityQueue对象时提供的比较器对象private final Comparator<? super E> comparator;// 用户如果没有提供比较器对象,使用默认的内部比较,将comparator置为nullpublic PriorityQueue() {this(DEFAULT_INITIAL_CAPACITY, null);}// 如果用户提供了比较器,采用用户提供的比较器进行比较public PriorityQueue(int initialCapacity, Comparator<? super E> comparator) {// Note: This restriction of at least one is not actually needed,// but continues for 1.5 compatibilityif (initialCapacity < 1)throw new IllegalArgumentException();this.queue = new Object[initialCapacity];this.comparator = comparator;}// ...// 向上调整:// 如果用户没有提供比较器对象,采用Comparable进行比较// 否则使用用户提供的比较器对象进行比较private void siftUp(int k, E x) {if (comparator != null)siftUpUsingComparator(k, x);elsesiftUpComparable(k, x);}// 使用Comparable@SuppressWarnings("unchecked")private void siftUpComparable(int k, E x) {Comparable<? super E> key = (Comparable<? super E>) x;while (k > 0) {int parent = (k - 1) >>> 1;Object e = queue[parent];if (key.compareTo((E) e) >= 0)break;queue[k] = e;k = parent;}queue[k] = key;}// 使用用户提供的比较器对象进行比较@SuppressWarnings("unchecked")private void siftUpUsingComparator(int k, E x) {while (k > 0) {int parent = (k - 1) >>> 1;Object e = queue[parent];if (comparator.compare(x, (E) e) >= 0)break;queue[k] = e;k = parent;}queue[k] = x;}
}

三、使用PriorityQueue创建大小堆,解决TOPK问题

使用比较器创建小根堆

//使用比较器创建小根堆
class LessIntComp implements Comparator<Integer>{@Overridepublic int compare(Integer o1, Integer o2) {return o1 - o2;}
}

使用比较器创建大根堆 

//使用比较器创建大根堆
class GreaterIntComp implements Comparator<Integer>{@Overridepublic int compare(Integer o1, Integer o2) {return o2 - o1;}
}

 解决TOPK问题

public class TestDemo<E> {//求最小的K个数,通过比较器创建大根堆public static int[] smallestK(int[] array, int k) {if(k <= 0) {return new int[k];}GreaterIntComp greaterCmp = new GreaterIntComp();PriorityQueue<Integer> maxHeap = new PriorityQueue<>(greaterCmp);//先将前K个元素,创建大根堆for(int i = 0; i < k; i++) {maxHeap.offer(array[i]);}//从第K+1个元素开始,每次和堆顶元素比较for (int i = k; i < array.length; i++) {int top = maxHeap.peek();if(array[i] < top) {maxHeap.poll();maxHeap.offer(array[i]);}}//取出前K个int[] ret = new int[k];for (int i = 0; i < k; i++) {int val = maxHeap.poll();ret[i] = val;}return ret;}public static void main(String[] args) {int[] array = {4,1,9,2,8,0,7,3,6,5};int[] ret = smallestK(array,3);System.out.println(Arrays.toString(ret));}
}

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

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

相关文章

秒懂C++之string类(下)

目录 一.接口说明 1.1 erase 1.2 replace&#xff08;最好别用&#xff09; 1.3 find 1.4 substr 1.5 rfind 1.6 find_first_of 1.7 find_last_of 二.string类的模拟实现 2.1 构造 2.2 无参构造 2.3 析构 2.4.【】运算符 2.5 迭代器 2.6 打印 2.7 reserve扩容 …

大模型算法面试题(十二)

本系列收纳各种大模型面试题及答案。 1、领域模型Continue PreTrain数据如何选取 在领域模型的Continue PreTrain&#xff08;持续预训练&#xff09;过程中&#xff0c;数据选取是一个至关重要的步骤&#xff0c;它直接影响模型在特定领域上的性能和泛化能力。以下是一些关于…

Transformer-Bert---散装知识点---mlm,nsp,较之经典tran的区别和实际应用方式

本文记录的是笔者在了解了transformer结构后嗑bert中记录的一些散装知识点&#xff0c;有时间就会整理收录&#xff0c;希望最后能把transformer一个系列都完整的更新进去。 1.自监督学习 bert与原始的transformer不同&#xff0c;bert是使用大量无标签的数据进行预训练&#…

batch norm记录

文章目录 概要整体架构流程训练阶段推理阶段模型中使用的注意事项 概要 面试百度时候被问到了BN 内部详细的训练阶段&#xff0c;推理阶段的计算过程。没回答好&#xff0c;来记录一下 推荐一下b站up: Enzo_Mi。视频做的确实不错 bn 讲解视频 整体架构流程 训练阶段 均值和标…

【C/C++】printf和cout的区别

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞 关注支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; &#x1f525;c系列专栏&#xff1a;C/C零基础到精通 &#x1f525; 给大…

C++初阶学习——探索STL奥秘——标准库中的string类

1. 为什么学习string类&#xff1f; 在我们学习C语言的时候&#xff0c;有一个点是非常难处理的&#xff0c;那就是字符串&#xff0c;在我们对字符串访问&#xff0c;增删查改时都是非常不便的&#xff0c;所以我们封装了一个string类主要来处理字符串有关的问题 2. 标准库中…

多模态论文一:CLIP模型主要内容讲解【原理+代码】

一、CLIP模型主要内容讲解 CLIP&#xff08;Contrastive Language-Image Pre-training&#xff09;是OpenAI在2021年发布的一种用于图像和文本联合表示学习的模型。CLIP的核心思想是通过对比学习来预训练一个模型&#xff0c;使其能够理解图像和文本之间的关系。以下是CLIP的工…

数据传输安全--SSL VPN

目录 IPSEC在Client to LAN场景下比较吃力的表现 SSL VPV SSL VPN优势 SSL协议 SSL所在层次 SSL工作原理 SSL握手协议、SSL密码变化协议、SSL警告协议三个协议作用 工作过程 1、进行TCP三次握手、建立网络连接会话 2、客户端先发送Client HELLO包&#xff0c;下图是包…

Oracle对比两表数据的不一致

MINUS 基本语法如下 [SQL 语句 1] MINUS [SQL 语句 2];举个例子&#xff1a; select 1 from dual minus select 2 from dual--运行结果 1-------------------------------- select 2 from dual minus select 1 from dual--运行结果 2所以&#xff0c;如果想找所有不一致的&a…

【数据结构】二叉树链式结构——感受递归的暴力美学

前言&#xff1a; 在上篇文章【数据结构】二叉树——顺序结构——堆及其实现中&#xff0c;实现了二叉树的顺序结构&#xff0c;使用堆来实现了二叉树这样一个数据结构&#xff1b;现在就来实现而二叉树的链式结构。 一、链式结构 链式结构&#xff0c;使用链表来表示一颗二叉树…

FPGA:有限状态机

从以下6个实验理解状态机的概念 开发板频率为 50 M H z 50MHz 50MHz&#xff0c;一个时钟周期是 20 n s 20ns 20ns。 1、实验一:LED灯亮0.25秒、灭0.75秒的状态循环 通过之前的分析&#xff0c;我们实现频闪灯时&#xff0c;是让led灯在0.5秒实现一次翻转&#xff0c;而这里…

经典文献阅读之--World Models for Autonomous Driving(自动驾驶的世界模型:综述)

Tip: 如果你在进行深度学习、自动驾驶、模型推理、微调或AI绘画出图等任务&#xff0c;并且需要GPU资源&#xff0c;可以考虑使用UCloud云计算旗下的Compshare的GPU算力云平台。他们提供高性价比的4090 GPU&#xff0c;按时收费每卡2.6元&#xff0c;月卡只需要1.7元每小时&…

html+css 实现水波纹按钮

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享htmlcss 绚丽效果&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 文…

vue3前端开发-小兔鲜项目-使用pinia插件完成token的本地存储

vue3前端开发-小兔鲜项目-使用pinia插件完成token的本地存储&#xff01;实际业务开发中&#xff0c;token是一个表示着用户登录状态的重要信息&#xff0c;它有自己的生命周期。因此&#xff0c;这个参数值必须实例化存储在本地中。不能跟着pinia。因为pinia是基于内存设计的模…

事务和函数索引

事务 事务的定义 事务&#xff08;Transaction&#xff09;&#xff0c;就是将一组SQL语句放在同一批次内去执行&#xff0c;如果一个SQL语句出错&#xff0c;则该批次内 的所有SQL都将被取消执行。 事务的特点 一个事务中如果有一个数据库操作失败&#xff0c;那么整个 事务…

若依框架 : 生成代码

6.生成代码 6.1.配置生成设置 ruoyi-generator -> src -> main -> resources -> generator.yml 由于 案例中 表都有 前缀 为 tta_ , 这里设置去掉 6.2.生成代码 6.2.1.导入数据库中的表 6.2.2.修改设置 6.2.2.1.设置生成信息 点击 编辑 -> 生成信息 特别…

m4a怎么转mp3?m4a转mp3的几种方法教程

m4a怎么转mp3&#xff1f;M4A音频格式的全称MPEG-4 Audio&#xff0c;是一种音频压缩格式。这种格式以其卓越的音质和相对较小的文件大小而广受欢迎&#xff0c;尤其是在音乐存储、在线流媒体以及音频编辑等领域。M4A格式被广泛应用于苹果公司的产品中&#xff0c;如iPhone、iP…

开放式耳机会成为未来的主流吗?开放式耳机推荐指南

开放式耳机是否会成为未来的主流&#xff0c;是一个值得探讨的问题。 从目前的市场趋势和技术发展来看&#xff0c;有一些因素支持开放式耳机可能成为主流。 一方面&#xff0c;人们对于健康和舒适的关注度不断提高。长时间佩戴传统耳机可能导致耳部不适&#xff0c;而开放式…

在Linux中,部署及优化Tomcat

tomcat概述 自 2017 年 11月编程语言排行榜 Java 占比 13%,高居榜首&#xff0c;Tomcat 也一度成为 Java开发人员的首选。其开源、占用系统资源少、跨平台等特性深受广大程序员喜爱。本章主要学习如何部署 Tomcat 服务&#xff0c;根据生产环境实现多个虚拟主机的配置&#xf…

【QGroundControl二次开发】五.python生成自定义MAVLink消息及使用

一 . 环境配置 参考&#xff1a; MAVLink代码生成-C# 二. 生成MAVLINK协议 在MAVlink源码下找到message_definitions/common.xml&#xff0c;修改其中的内容。 例如&#xff1a; <message id"12" name"DISTANCE_SENSOR"><description>Dedi…