Java对象的比较

对象比较的三种方式:1. equals方法,

                                    2. 实现comparable接口重写compareTo方法,

                                    3.实现comparator接口重写compare方法。

                                    4.还有一种就是基本数据类型像int用“==”去比较。(重点总结前三种)

首先,在对象的比较中,像基本数据类型int这样的是可以用 "==" 去比较的,但是如果要进行比较的是两个对象,比如我创建一个学生类,类当中有我的成员变量,有类的构造方法,

 

 然后在main方法中实例化两个对象,如上图代码,虽然我实例化了两个name和age都是一样的对象,但在Java中看来,这是两个对象,所以在比较的时候用==进行比较然后打印肯定是false(==进行比较的时候只能是比较是否相等),虽然我看代码这两个人是一样的name和age,我就认为他们是同一个人,但是在比较的时候是引用和引用之间的比较,当实例化两个对象的时候,会在内存上开辟两块空间,引用存放的是这个空间的地址(这个地址指向实例化的对象),这两个地址是不一样的,所以不能用 == 进行比较。

那我能不能用queals去比较呢这两个对象呢,也是不行的。因为在我创建的这个类中,是没有equals这个方法的,但是所有的类均继承于object类,所以调用equals方法会调用到父类object的equals方法,可以看一下object类中的equals方法的源码:

 如上图,这个equals方法return的也是用“==”去比较的,this代表当前对象的引用,obj是传进来的参数,所以用object类中的equals方法也是不可以的。

同样的,equals方法也是只能进行比较是否相等。

那要进行对象之间的比较要用什么方法呢:

1.首先我们可以在student类中重写equals方法,自己写一个比较规则,如下图:

return一个age相等并且name相同才这两个对象才是相同的,或者年龄相等就说这两个对象是相同的,具体的规则可以自己写。

2.用equals方法只能比较两个对象是否相同,但是不能排序之类的,所以就有了后边的方法,我们可以用student类实现comparable接口,然后重写接口中的comparTo方法,在重写的方法中也是可以自己写定一个比较规则的,如下图:

 上图代码就是重写了compareTo方法,return的是一个int类型,所以在比较的时候,(同样的this还是当前对象的引用,就是谁调用这个方法谁就是this,然后o是传进来的参数)如果第一个对象的age>第二个对象的age,就返回一个正数,反之返回一个负数,如果是相等的就返回一个0,然后两个对象就可以进行比较了,但是这个方法也有一个缺点:就是对类的侵入性比较大(就是说如果写完了用age去进行比较的时候,以后在调用这个方法的时候就只能用类去进行比较),那以后我要用name去比较呢?就是不可以的。

所以就有了第三个方法,单独写一个类,去实现Comparator接口,然后重写Comparator接口中的compare方法。(称作比较器)

 定义一个单独的类来写比较规则,然后用这个比较器去进行比较,

 如上图代码,一个类,实现了Comparator接口,重写了方法,return的也是一个int类型,

(首先name是字符串,不能用减号去进行比较,应该用CompareTo方法,这个方法是String自己的CompareTo的方法) 这个时候因为cmp是一个单独的类,所以在调用方法去进行比较的时候很灵活,我们可以根据比较器来比较者两个对象,可以用name去进行比较,也可以用age去进行比较(就再写一个age的比较器),你需要用什么参数去比较,就去调用哪一个比较器就可以了,在调用的时候,因为比较器写成了一个类,所以先实例化一个比较器的对象,然后再用比较器的这个引用去调用比较传参就可以了。

PriorityQueue的比较方式

比较器的应用:

比较器涉及到了PriorityQueue(优先级队列)中的topK问题(前10名,500强...),因为PriorityQueue的底层是一个小根堆,在进行比较的时候,如果是前K名大的数据,比较就用小根堆,如果要是前K名小的数据比较就用大根堆,(总结:找前k名小的数据,就建立一个有k个节点的大根堆,因为你是一个大根堆,所以堆顶的元素是最大的,就遍历数组中剩下的数据,因为堆的底层就是一个数组,如果有比堆顶元素小的数据,那么堆顶元素一定不是前k个最小的,同样的,找前k个最大的数据也是一样的)。

那么,优先级队列底层是一个小根堆(可以去看一下Java中的源码),如果要是比较前k个大的数据还好,那我要比较前k个小的数据呢,我需要一个大根堆。

所以这个就涉及到了比较器,如何把一个优先级队列中的小根堆改成一个大根堆。

首先我们认识一下,PriorityQueue为什么是一个小根堆,可以看下图中的代码:

如果第一个存放的是一个20,第二个存放的是30,就直接放到后面就可以了,如果第二个存放一个10,就和20这个数据去交换,所以底层就是一个小根堆,我们可以认为它和student类是一样的,是写死 的,

 

 

 相当于o就是传过来的那个参数,和上面那个参数e是一样的,this和上面的key是一样的,如果是o.age-this.age,就变成了大根堆,因为和小根堆的情况是相反的。

那我们要把PriorityQueue的小根堆变成大根堆,也是一样的,写一个单独的类,然后把两个参数调换一下位置,

 在调用这个大根堆的时候是这样调用的,

 先实例化这个比较器的对象,然后以传参的方式把比较器传过去,我们可以看一下PriorityQueue的源码,是可以传一个比较器的,

 

 如果比较器是空的,它就调用它自己的比较器,如果你传过去一个比较器,这个比较器就会调用你自己写的比较器, 然后去进行比较,这个时候我们传过去的是一个大根堆,所以在比较的时候,比较的是前k个最小的数据,就完成了小根堆到大根堆的转化。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

良月初十♧

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值