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


    作者主页: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 priorityQueue = new PriorityQueue<>();
    12. priorityQueue.offer(new student(12,"小猪佩奇"));
    13. priorityQueue.offer(new student(12,"小猪乔治"));
    14. }

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

    元素的比较

    基本类型的比较

    在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 {
    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{
    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 {
    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 {
    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, Comparatorsuper 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. Comparablesuper E> key = (Comparablesuper 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. }

    画图分析:


  • 相关阅读:
    2022-11-11 C++并发编程( 四十一 )
    nodejs+vue实验室上机管理系统的设计与实现-微信小程序-安卓-python-PHP-计算机毕业设计
    【嵌入式Linux】第二部分 - 裸机开发/系统移植/驱动开发/内核开发
    linux redis hash哈希 增删改查
    win10 ISO
    一文读懂IP定位技术的优缺点
    Spring声明式基于注解的缓存(3-精进篇)
    SSRF 漏洞笔记
    Python 算法高级篇:深入理解复杂度分析-时间复杂度与空间复杂度
    java基础—oop三大特性
  • 原文地址:https://blog.csdn.net/paperjie/article/details/133906500