Java中对象的比较

news2024/9/20 6:22:35

从大根堆说到对象的比较

  • 大小根堆
  • 对象的比较
    • equals
    • Comparable
    • Comparator

大小根堆

大小根堆是堆相关的知识,堆这种数据结构总结起来就是:堆顶元素是最大的就是大根堆,而每个堆顶元素以下的又可以看成一个堆:
在这里插入图片描述
要注意的是,堆底层是用数组实现的:
在这里插入图片描述
但是对这种数据结构具体化之后与二叉树是高度类似的.

        PriorityQueue<Integer> priorityQueue=new PriorityQueue<>();
        priorityQueue.offer(1);
        priorityQueue.offer(2);
        System.out.println(priorityQueue.peek());

在这里插入图片描述
代码告诉了我们,我们创建出来的堆默认都是小根堆,实际上我们也可以去源码里看看:
在这里插入图片描述
在这里插入图片描述
认识一个类,首先就要认识类的构造方法:可以看到,不带任何参数的PriorityQueue( ),会调用带两个参数的构造方法,第一个参数是常量,也是意味着堆底层数组的默认容量是11(这是从源码里面点进去看到的),第二个参数人家本来是想让我们传一个比较器的,这里不传的话就给个null.
我觉得比较重要就是这个offer方法:

    public boolean offer(E e) {//打个比方,这是个Integer的泛型类,但是我们
    传参数的话给个1,2是没问题的,这个会自动装箱
        if (e == null)
            throw new NullPointerException();//第一个注意点:给堆添加
            元素的时候,不可以给null,否则会抛异常
        modCount++;//这个暂时不要管,之前在哪里也看到过这个变量名的
        int i = size;
        if (i >= queue.length)
            grow(i + 1);//扩容方法grow,当然这个也不可能给你无限扩容下去
            最大好像就是int的最大值来着
        size = i + 1;
        if (i == 0)
            queue[0] = e;
        else
            siftUp(i, e);//在这里我们之前第二个比较器参数就要派上用场了
        return true;
    }
    private void siftUp(int k, E x) {
        if (comparator != null)
            siftUpUsingComparator(k, x);//这就是比较器
        else
            siftUpComparable(k, x);//这是堆默认的比较
    }


        private void siftUpComparable(int k, E x) {
        Comparable<? super E> key = (Comparable<? super E>) x;
        //看好,这边把我们本来要插入的数据强转了:
        //(Comparable<? super E>) x 这个Comparable很显然就是一个接口,那么
        //既然我们敢对X进行强转,说明这个x背后的类一定要实现Comparable这个
        //接口,也正因如此我斗胆得出一个局部结论:我们要往堆插入的元素一定要是
        //可以比较的!!
        
        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;
    }

//比较器这个也是大同小异
    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;
    }

对象的比较

只是站在使用堆的角度上,我们只要简单了解一下底层的原理就行,当然,我们也可以点进堆中,详细走一遍.
在刚才的讲解中,有一个重大的漏洞我还没有补上,甚至于说,这篇博客前面关于堆的知识,其实就是我为了引出这个知识点而做出的铺垫:
在Java中我们该如何实现对象的比较呢?

equals

如果是部分简单的基本数据类型,我们直接大于等于小于,那就OK了.
但是对于大部分引用类型,我们是不可以大于小于的,并且我们使用等于比较的仅仅是两个引用的地址.
可曾听闻equals?

class Person{
    int id;
    String name;

    public Person(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public Person() {
    }
}


        Person A=new Person(1,"A");
        Person a=new Person(1,"A");
        boolean flag=A.equals(a);
        System.out.println(flag);

按照我们的设想,A和a这兄弟两身份证一样,就应该是同一个人了,但事实呢:
在这里插入图片描述
在这里插入图片描述
所有类都默认继承了Object类,这个类中的equals方法定睛一看,原来比较的也是地址啊…为了让故事的走向合乎于理,我们必须要自己手写剧本:
我们要自己重写equals方法!!
在这里插入图片描述

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return id == person.id;
    }

然后就一路点下去就可以了,这下子故事的走向就应该和我们设想的一样了:

        Person A=new Person(1,"A");
        Person a=new Person(1,"a");
        boolean flag=A.equals(a);
        System.out.println(flag);

在这里插入图片描述
即使这两个人名字不一样,只要身份证一致那你俩就是一个人!!
其实官方重写的这个equals方法看似繁琐,但是设计的还是非常之巧妙的,看官老爷们不妨三连之后再去细品!!

Comparable

刚才讲的equals是很方便,但是光光只是一个孤零零的方法并不具有面向对象的特性,接下来我们要讲的两个接口才是我们在底层代码中常见的:
Comparable
就拿我们刚才讲的堆举例子吧,我们要往堆里面插入Person类对象的话可以吗?
在这里插入图片描述
看似没问题哈,我还告诉你们,就是运行一下子都不会有任何报错,我们再来一个试试:
在这里插入图片描述
来个特写:
在这里插入图片描述类型转换错误,这就是我们之前跑底层的时候说的x被强制转化成了Comparable,这也就意味着我们x背后的类一定要实现这个接口,不然就会发生上面的错误,我们说的,实现接口然后要重写接口中的方法:

    @Override
    public int compareTo(Person o) {
        return this.age-o.age;
    }

在这里插入图片描述
从宏观上我们确实达到了我们的目的,那么从微观上究竟是如何实现这个操作的呢?其实之前跑代码的时候我们就说过了:
在这里插入图片描述
细心的看官老爷会发现其实之前我们的equals方法返回的是布尔类型,但是这里我们的compareTo包括后面的compare返回的都应该是int类型,谁调用compareTo方法谁就是源码里面的this,( )里面的参数就是o.

Comparator

刚刚我们讲的那么Comparable接口啊,虽然好使,但是有一个弊端,这个方法对于代码的侵入性太强,意思就是,如果有一天我不想使用年龄作为参考进行比较了,然后我还自己偷摸给它改了,那么麻烦就大了,整个程序肯定是到处见红啊!
那么我们还有一招可以使:Comparator

class AgeComparator implements Comparator<Person>{

    @Override
    public int compare(Person o1, Person o2) {
        return o1.age- o2.age;
    }
}

        AgeComparator ageComparator=new AgeComparator();
        PriorityQueue<Person>priorityQueue2
        =new PriorityQueue<>(ageComparator);
        Person C=new Person(1,6);
        Person D=new Person(2,2);
        priorityQueue2.offer(C);
        priorityQueue2.offer(D);

这招看似麻烦一点,但是无论是效果还是后续的影响上来看,都不输给Comparable!
在这里插入图片描述
而且使用Comparator还有一点好处,就是哪一天我不高兴了,我可以直接另外写一个比较器,我比较名字:

    @Override
    public int compare(Person o1, Person o2) {
        return o1.name.compareTo(o2.name);
    }

当然了这个compareTo呢也不是天上掉下来了,也是Object里面的.

说到这里,兄弟们,现在大家应该有一点感悟了吧,那我请问一下兄弟们:为什么即使默认为小根堆呢?如果兄弟们看源码的话,应该会发现无论是无论是哪个接口的方法下面,必须要是满足了接口下面比较方法的条件是才会调整,所以如果我们改变比较方法的正负,那么自然而然的也就会变成大根堆喽!!!

emmm相信读到这里兄弟们关于堆和对象的比较应该也就是拨开云雾见天明了吧.我相信这篇博客能够切实地帮到一些道友!
给各位看官老爷拜个晚年,祝大家兔年一帆风顺!
百年大道,你我共勉!!

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

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

相关文章

JVM OOM和CPU问题排查

目录 1、JVM调优工具 1.1、jps 1.2、jstat 1.3、jstack 1.4、jinfo 1.5、jmap 2、OOM排查过程 2.1、OOM原因 2.2、OOM发生区域 2.2.1、Java堆溢出&#xff1a;heap 2.2.2、Java栈溢出&#xff1a;stack 2.2.3、运行时常量溢出&#xff1a;constant 2.2.4、方法区…

计算机毕业设计选题推荐nodejs+vue355的网上购物商城系统

网上购物商城&#xff0c;在系统首页可以查看首页、关于我们、商品信息、新闻信息、交流论坛、留言反馈、个人中心、后台管理、在线客服等内容 前端技术&#xff1a;nodejsvueelementui 前端&#xff1a;HTML5,CSS3、JavaScript、VUE 1、 node_modules文件夹(有npn install产…

spring整合mybatis的核心思路(数据源切换)

文章目录1. 整合思路2. 最简单的整合步骤1. 导入依赖2. 准备基础类UserUserMapperuserMapper.xmlMybatisConfig3. 测试TestMybatisSpring3. 整合多个mybatis配置1. 修改MybatisConfig2. 测试TestMybatisSpring4. AbstractRoutingDataSource实现源切换1. 准备基础类PersonPerson…

JVM的栈内存

每当启动一个新线程时&#xff0c;Java虚拟机都会为它分配一个Java栈。Java栈以帧为单位保存线程的运行状态。虚拟机只会直接对Java栈执行两种操作&#xff1a;以帧为单位的压栈和出栈。 某个线程正在执行的方法被称为该线程的当前方法&#xff0c;当前方法使用的栈帧称为当前帧…

车载以太网 - SomeIP测试 - 初识 - 01

SOA,Service-Oriented Architecture,即面向服务的架构 SOA是一种面向服务的架构,定义了“服务器”和“客户端”,前者是服务、数据的提供者,后者是订阅了所需要的服务或者数据。应用程序之间是公三耦合,并通过服务总线作为中间件进行通信。SOA更像是一种框架,需要将信息从…

【JavaGuide面试总结】Java集合篇·下

【JavaGuide面试总结】Java集合篇下1.HashMap 的长度为什么是 2 的幂次方2.HashMap 有哪几种常见的遍历方式?3.HashSet 如何检查重复?4.ConcurrentHashMap 和 Hashtable 的区别5.ConcurrentHashMap 线程安全的具体实现方式/底层具体实现JDK1.8 之前JDK1.8 之后6.JDK 1.7 和 J…

从零编写linux0.11 - 第九章 文件系统(一)

从零编写linux0.11 - 第九章 文件系统&#xff08;一&#xff09; 编程环境&#xff1a;Ubuntu 20.04、gcc-9.4.0 代码仓库&#xff1a;https://gitee.com/AprilSloan/linux0.11-project linux0.11源码下载&#xff08;不能直接编译&#xff0c;需进行修改&#xff09; 本章…

【青训营】Go的一些性能优化技巧

一、Slice切片的性能优化 对Slice进行内存预分配 尽可能在使用make()初始化函数的时候提供容量信息&#xff0c;因为切片本质是一个数组片段的描述&#xff0c;其源码如下&#xff1a; type slice struct{array unsafe.Pointerlen int// 长度cap int// 容量 }如果没有指定容…

22.1.28打卡 Codeforces Round #847 (Div. 3) A~E

https://codeforces.com/contest/1790A. Polycarp and the Day of Pi题意问你第一个和"314159265358979323846264338327"不同的字符串下标1是什么如果全部相同输出最后一个下标1/* ⣿⣿⣿⣿⣿⣿⡷⣯⢿⣿⣷⣻⢯⣿⡽⣻⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣇⠸⣿⣿⣆…

Python基于LSTM预测特斯拉股票

Python基于LSTM预测特斯拉股票 提示&#xff1a;前言 Python基于LSTM预测特斯拉股票 股票预测是指&#xff1a;对股市具有深刻了解的证券分析人员根据股票行情的发展进行的对未来股市发展方向以及涨跌程度的预测行为。这种预测行为只是基于假定的因素为既定的前提条件为基础的…

通用智能基础模型假说

🍿*★,*:.☆欢迎您/$:*.★* 🍿 https://dongfangyou.blog.csdn.net/article/details/128761358 通过上面说的 人本身自带一个 各种行为反馈的评价模型 拥有这个模型便可拥有通用智能 简单的分析一下该模型到底应该由什么组成 最基础的模型是什么 首先人类最基础的模型应该…

【小程序】类taro语法中小程序端使用f2

前言 最近在类taro框架中小程序端使用最新版f2。&#xff08;这里我使用rax&#xff09;并封装了库&#xff0c;特此记录一下。 使用 想直接用的同学直接在你的rax项目中安装rax-my-f2这个包&#xff0c;他依赖antv/f2与antv/f2-context这2个包。 import { MyCanvas } from…

Kubernetes 笔记(06)— 搭建多节点集群、kubeadm 安装 master/worker/console/flannel 网络插件

1. kubeadm 官网&#xff1a;https://kubernetes.io/zh-cn/docs/reference/setup-tools/kubeadm/ 为了简化 Kubernetes 的部署工作&#xff0c;社区里就出现了一个专门用来在集群中安装 Kubernetes 的工具&#xff0c;名字就叫 kubeadm&#xff0c;意思就是 Kubernetes 管理员…

Java设计模式-状态模式State

介绍 状态模式&#xff08;State Pattern&#xff09;&#xff1a;它主要用来解决对象在多种状态转换时&#xff0c;需要对外输出不同的行为的问题。状态和行为是一一对应的&#xff0c;状态之间可以相互转换。当一个对象的内在状态改变时&#xff0c;允许改变其行为&#xff…

学习记录677@项目管理之配置管理案例

案例 Simple公司的质量管理体系中的配置管理程序文件中有如下规定: (1)由变更控制委员会(CCB)制定项目的配置管理计划; (2)由配置管理员(CMO)创建配置管理环境: (3)由CCB 审核变更计划; (4)项目中配置基线的变更经过变更申请、变更评估、变更实施后便可发布&#xff1b; (5)CC…

Java基础10:常用API(下)

Java基础10&#xff1a;常用API&#xff08;下&#xff09;一、Date二、SimpleDateFormat三、Calendar四、ZoneId五、Instant六、ZoneDateTime七、DateTimeFormatter八、LocalDate、LocalTime、LocalDateTime九、Duration、Period、ChronoUnit十、包装类一、Date Date类是一个…

基于PIL和Tesseract的数字计算验证码识别处理思路

如图,我们在使用python自动化的时候经常会遇到很多各式各样的验证码。这个是一个数字加法的验证码。 干扰项里包含完整的数字、字母信息,普通的OCR识别可能不是很准确。 但是不管怎们样,咱们先把必要的环境搭建起来,试一下Tesseract的识别结果吧。 1、安装Tesseract: 首…

屏蔽360阻止运程执行变更注册表自启动数据的办法

屏蔽360阻止运程执行变更注册表自启动数据的办法 运程服务器上的程序&#xff0c;由于需要。我在服务器中&#xff0c;加入更新升级自身&#xff08;exe&#xff09;文件&#xff0c;并变更操作系统自启动数据的代码。 实践证明&#xff0c;通过客户端&#xff0c;调用运程服务…

全景解析SSD IO QoS性能优化

一、NAND基本原理目前NAND已经从SLC发展到PLC&#xff0c;但是PLC离大规模上市还有一段距离&#xff0c;我们暂时先略过。市面上主要流通的就是4种NAND类型&#xff1a;SLC、MLC、TLC、QLC。随着每个寿命从高到低依次是SLC>MLC>TLC>QLC.随着单个cell含有的bit数越多&a…

Unity MRTK使用详解(Htc vive+LeapMotion)

MRTK-Unity是一个由Microsoft驱动的开源项目&#xff0c;提供了多种组件和功能&#xff0c;用于加速Unity中的跨平台MR应用程序开发。以下是其一些功能&#xff1a; 提供跨平台输入系统和用于空间交互和UI组件。 启用快速原型通过在编辑器中的模拟&#xff0c;让你马上看到变化…