Java对象的比较

蔚落 2023-10-12 20:54 106阅读 0赞

70dfdffb16c54eb8beab588e3d08a751.jpeg

目录

一、 PriorityQueue中插入对象

二、元素的比较

1、基本类型的比较

2、对象比较的问题

三、对象的比较

1、覆写基类的equals

2、基于Comparble接口类的比较

3、基于比较器比较

4、三种方式对比

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


一、 PriorityQueue**中插入对象**

我们之前已经学过了优先级队列, 优先级队列在插入元素时有个要求:插入的元素不能是null或者元素之间必须要能够进行比较 ,为了简单起见,我们当时只是插入了 Integer 类型,那么优先级队列中能否插入自定义类型对象来进行比较呢?

我们现在定义了一个card类,然后尝试比较card类

  1. class Card {
  2. public int rank; // 数值
  3. public String suit; // 花色
  4. public Card(int rank, String suit) {
  5. this.rank = rank;
  6. this.suit = suit;
  7. }
  8. }
  9. public class TestPriorityQueue {
  10. public static void TestPriorityQueue()
  11. {
  12. PriorityQueue<Card> p = new PriorityQueue<>();
  13. p.offer(new Card(1, "♠"));
  14. p.offer(new Card(2, "♠"));
  15. }
  16. public static void main(String[] args) {
  17. TestPriorityQueue();
  18. }
  19. }

此时我们会发现:

优先级队列底层使用堆,而向堆中插入元素时,为了满足堆的性质,必须要进行元素的比较,而此时 Card 是没有办法直接进行比较的,因此抛出异常。

73d3788ef61148b0af8b73fd9beb766e.png


二、元素的比较

1、基本类型的比较

在Java中,基本类型的对象可以直接比较大小。

  1. public class TestCompare {
  2. public static void main(String[] args) {
  3. int a = 10;
  4. int b = 20;
  5. System.out.println(a > b);
  6. System.out.println(a < b);
  7. System.out.println(a == b);
  8. char c1 = 'A';
  9. char c2 = 'B';
  10. System.out.println(c1 > c2);
  11. System.out.println(c1 < c2);
  12. System.out.println(c1 == c2);
  13. boolean b1 = true;
  14. boolean b2 = false;
  15. System.out.println(b1 == b2);
  16. System.out.println(b1 != b2);
  17. }
  18. }

2、对象比较的问题

我们现在来试一下比较card类:

  1. class Card {
  2. public int rank; // 数值
  3. public String suit; // 花色
  4. public Card(int rank, String suit) {
  5. this.rank = rank;
  6. this.suit = suit;
  7. }
  8. }
  9. public class TestPriorityQueue {
  10. public static void main(String[] args) {
  11. Card c1 = new Card(1, "♠");
  12. Card c2 = new Card(2, "♠");
  13. Card c3 = c1;
  14. //System.out.println(c1 > c2); // 编译报错
  15. System.out.println(c1 == c2); // 编译成功 ----> 打印false,因为c1和c2指向的是不同对象
  16. //System.out.println(c1 < c2); // 编译报错
  17. System.out.println(c1 == c3); // 编译成功 ----> 打印true,因为c1和c3指向的是同一个对象
  18. }
  19. }

根据代码的运行结果我们会发现:

c1 、 c2 和 c3 分别是 Card 类型的引用变量,上述代码在比较编译时:

c1 > c2 编译失败

c1== c2 编译成功

c1 < c2 编译失败

从编译结果可以看出, Java中引用类型的变量不能直接按照 > 或者 < 方式进行比较 。 那为什么 == 可以比较?

因为: 对于用户实现自定义类型,都默认继承自Object类,而Object类中提供了equal方法,而==默认情况下调用的就是equal方法 ,但是该方法的比较规则是: 没有比较引用变量引用对象的内容,而是直接比较引用变量的地址 ,但有些情况下该种比较就不符合题意。

  1. // Object中equal的实现,可以看到:直接比较的是两个引用变量的地址
  2. public boolean equals(Object obj) {
  3. return (this == obj);
  4. }

三、对象的比较

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

1、覆写基类的**equals**

  1. public class Card {
  2. public int rank; // 数值
  3. public String suit; // 花色
  4. public Card(int rank, String suit) {
  5. this.rank = rank;
  6. this.suit = suit;
  7. }
  8. @Override
  9. public boolean equals(Object o) {
  10. // 自己和自己比较
  11. if (this == o) {
  12. return true;
  13. }
  14. // o如果是null对象,或者o不是Card的子类
  15. if (o == null || !(o instanceof Card)) {
  16. return false;
  17. }
  18. // 注意基本类型可以直接比较,但引用类型最好调用其equal方法
  19. Card c = (Card)o;
  20. return rank == c.rank
  21. && suit.equals(c.suit);
  22. }
  23. }

注意: 一般覆写 equals 的套路就是上面演示的

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

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

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

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

  5. 注意下调用其他引用类型的比较也需要 equals ,例如这里的 suit 的比较

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


2、基于**Comparble**接口类的比较

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

  1. public interface Comparable<E> {
  2. // 返回值:
  3. // < 0: 表示 this 指向的对象小于 o 指向的对象
  4. // == 0: 表示 this 指向的对象等于 o 指向的对象
  5. // > 0: 表示 this 指向的对象大于 o 指向的对象
  6. int compareTo(E o);
  7. }

对用户自定义类型,如果要想按照大小与方式进行比较时: 在定义类时,实现Comparble接口即可,然后在类中重写compareTo方法。

  1. public class Card implements Comparable<Card> {
  2. public int rank; // 数值
  3. public String suit; // 花色
  4. public Card(int rank, String suit) {
  5. this.rank = rank;
  6. this.suit = suit;
  7. }
  8. // 根据数值比较,不管花色
  9. // 这里我们认为 null 是最小的
  10. @Override
  11. public int compareTo(Card o) {
  12. if (o == null) {
  13. return 1;
  14. }
  15. return rank - o.rank;
  16. }
  17. public static void main(String[] args){
  18. Card p = new Card(1, "♠");
  19. Card q = new Card(2, "♠");
  20. Card o = new Card(1, "♠");
  21. System.out.println(p.compareTo(o)); // == 0,表示牌相等
  22. System.out.println(p.compareTo(q)); // < 0,表示 p 比较小
  23. System.out.println(q.compareTo(p)); // > 0,表示 q 比较大
  24. }
  25. }

Compareble 是 java.lang 中的接口类,可以直接使用。


3、基于比较器比较

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

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

  1. public interface Comparator<T> {
  2. // 返回值:
  3. // < 0: 表示 o1 指向的对象小于 o2 指向的对象
  4. // == 0: 表示 o1 指向的对象等于 o2 指向的对象
  5. // > 0: 表示 o1 指向的对象等于 o2 指向的对象
  6. int compare(T o1, T o2);
  7. }

注意:区分Comparable和Comparator。

覆写Comparator中的compare方法

  1. import java.util.Comparator;
  2. class Card {
  3. public int rank; // 数值
  4. public String suit; // 花色
  5. public Card(int rank, String suit) {
  6. this.rank = rank;
  7. this.suit = suit;
  8. }
  9. }
  10. class CardComparator implements Comparator<Card> {
  11. // 根据数值比较,不管花色
  12. // 这里我们认为 null 是最小的
  13. @Override
  14. public int compare(Card o1, Card o2) {
  15. if (o1 == o2) {
  16. return 0;
  17. }
  18. if (o1 == null) {
  19. return -1;
  20. }
  21. if (o2 == null) {
  22. return 1;
  23. }
  24. return o1.rank - o2.rank;
  25. }
  26. public static void main(String[] args){
  27. Card p = new Card(1, "♠");
  28. Card q = new Card(2, "♠");
  29. Card o = new Card(1, "♠");
  30. // 定义比较器对象
  31. CardComparator cmptor = new CardComparator();
  32. // 使用比较器对象进行比较
  33. System.out.println(cmptor.compare(p, o)); // == 0,表示牌相等
  34. System.out.println(cmptor.compare(p, q)); // < 0,表示 p 比较小
  35. System.out.println(cmptor.compare(q, p)); // > 0,表示 q 比较大
  36. }
  37. }

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


4、三种方式对比

上面,我们讲到了三种比较对象的方法,那么现在我们将它们三个进行对比:

741e1633b50a4ca1ad5877c321dd1799.png


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

集合框架中的 PriorityQueue 底层使用堆结构,因此其内部的元素必须要能够比大小, PriorityQueue 采用了:Comparble和 Comparator 两种方式。

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

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

发表评论

表情:
评论列表 (有 0 条评论,106人围观)

还没有评论,来说两句吧...

相关阅读

    相关 java对象比较

    本文章主要介绍了Java对象的比较,首先我们介绍了元素和对象之间分别是如何比较的,然后我们讲解了继承Comparable接口进行比较,最后讲解了什么是PriorithQu...

    相关 Java - 对象比较

    一、问题提出 > 前面讲了优先级队列,优先级队列在插入元素时有个要求:插入的元素不能是null或者元素之间必须要能够进行比较,为了简单起见,我们只是插入了Integer类

    相关 Java对象比较

    一 点睛 在Java中,有两种方式可用于对象间的比较: 利用"=="运算符:用于比较两个对象的内存地址值(引用值)是否相等。 利用equals()方法:用于比较