【数据结构】Java对象的比较

柔光的暖阳◎ 2024-02-21 10:01 108阅读 0赞

作者主页:paper jie_博客

本文作者:大家好,我是paper jie,感谢你阅读本文,欢迎一建三连哦。

本文录入于《JAVA数据结构》专栏,本专栏是针对于大学生,编程小白精心打造的。笔者用重金(时间和精力)打造,将javaSE基础知识一网打尽,希望可以帮到读者们哦。

其他专栏:《算法详解》《C语言》《javaSE》等

内容分享:本期将会分享java数据结构中的

目录

priorityQueue中如何插入对象

元素的比较

基本类型的比较

对象类型的直接比较

对象正确的比较方式

重写equals方法

基于Comparble接口类的比较

基于比较器比较

集合框架中priorityQueue的比较方式


priorityQueue中如何插入对象

我们知道,优先级队列在插入元素时有一个要求:需要可以比较的对象才能插入。这里我们需要知道怎样插入自定义类型对象:

比如我们插入这个student对象:

  1. class student {
  2. int age;
  3. String name;
  4. public student(int age, String name) {
  5. this.age = age;
  6. this.name = name;
  7. }
  8. }
  9. public class Test {
  10. public static void main(String[] args) {
  11. PriorityQueue<student> priorityQueue = new PriorityQueue<>();
  12. priorityQueue.offer(new student(12,"小猪佩奇"));
  13. priorityQueue.offer(new student(12,"小猪乔治"));
  14. }

在运行后发现它会报类型不兼容的异常,这是因为在堆中插入元素,为了满足堆的性质,需要进行对象的比较,但是我们的student类型对象时不能直接比较的,所以会报错

1a8a12cebd17465fa1d99a9f4d5a9f61.png

元素的比较

基本类型的比较

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

  1. 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. }

对象类型的直接比较

  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. }

这里我们知道,直接进行对象比较的是地址,只有相同才会返回true,不同就会报错。但是这里为毛==可以比较呢?这就得提到Object类了,因为自定义类也会继承Object类,这个类中提供了equal方法,==的情况下就是用的Object的equal方法。但是这个方式比较的就是引用对象的地址,没有比较对象的内容,这就头疼了。

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

对象正确的比较方式

重写equals方法

  1. class student {
  2. int age;
  3. String name;
  4. public student(int age, String name) {
  5. this.age = age;
  6. this.name = name;
  7. }
  8. @Override
  9. public boolean equals(Object obj) {
  10. if(this == obj) {
  11. return true;
  12. }
  13. if(obj == null || !(obj instanceof student)) {
  14. return false;
  15. }
  16. student o = (student) obj;
  17. return this.age == ((student) obj).age && this.name.equals(o.name);
  18. }
  19. }

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

如果传入的是null或者不是student,返回false

按照类的成员对象比较,只要成员对象相同就返回true

注意下调其他引用类型的比较也要调用equals

这里的缺陷就是:equals只能按照相等来比较,不能比较大小

基于Comparble接口类的比较

Comparable接口的源码:

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

对用户自定义类型,想要按照大小比较时,在定义类的时候,实现Comparable接口即可。然后在类中实现compareTo方法:

  1. class student implements Comparable<student>{
  2. int age;
  3. String name;
  4. public student(int age, String name) {
  5. this.age = age;
  6. this.name = name;
  7. }
  8. @Override
  9. public int compareTo(student o) {
  10. if(o == null) {
  11. return 1;
  12. }
  13. return this.age - o.age;
  14. }
  15. }

基于比较器比较

用户自定义比较器类,需要实现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接口

在自定义比较器类中重写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. } if
  18. (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包

集合框架中priorityQueue的比较方式

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

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

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

JDK中的源码:

  1. // 用户如果没有提供比较器对象,使用默认的内部比较,将comparator置为null
  2. public PriorityQueue() {
  3. this(DEFAULT_INITIAL_CAPACITY, null);
  4. }
  5. // 如果用户提供了比较器,采用用户提供的比较器进行比较
  6. public PriorityQueue(int initialCapacity, Comparator<? super E> comparator) {
  7. // Note: This restriction of at least one is not actually needed,
  8. // but continues for 1.5 compatibility
  9. if (initialCapacity < 1)
  10. throw new IllegalArgumentException();
  11. this.queue = new Object[initialCapacity];
  12. this.comparator = comparator;
  13. }
  14. private void siftUp(int k, E x) {
  15. if (comparator != null)
  16. siftUpUsingComparator(k, x);
  17. else
  18. siftUpComparable(k, x);
  19. }
  20. private void siftUpComparable(int k, E x) {
  21. Comparable<? super E> key = (Comparable<? super E>) x;
  22. while (k > 0) {
  23. int parent = (k - 1) >>> 1;
  24. Object e = queue[parent];
  25. if (key.compareTo((E) e) >= 0)
  26. break;
  27. queue[k] = e;
  28. k = parent;
  29. }
  30. queue[k] = key;
  31. }
  32. @SuppressWarnings("unchecked")
  33. private void siftUpUsingComparator(int k, E x) {
  34. while (k > 0) {
  35. int parent = (k - 1) >>> 1;
  36. Object e = queue[parent];
  37. if (comparator.compare(x, (E) e) >= 0)
  38. break;
  39. queue[k] = e;
  40. k = parent;
  41. }
  42. queue[k] = x;
  43. }

画图分析:

b4eb9af4cbc2462aac4e152c1b97df69.png


发表评论

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

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

相关阅读

    相关 java对象比较

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

    相关 Java - 对象比较

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

    相关 Java对象比较

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