当前位置: 首页 > news >正文

Java数据结构_一篇文章搞定java对象的比较_7

1. PriorityQueue中插入对象

上篇文章研究了优先级队列,优先级队列在插入元素中,要求插入的元素不能是null或者元素之间必须要能够进行比较,为了简单起见,上篇文章只是插入了Integer类型,那优先级队列中是否能插入自定义类型的对象呢

有如下代码:

class Card {
    private int rank; //数值
    private String suit; //花色

    public Card(int rank, String suit) {
        this.rank = rank;
        this.suit = suit;
    }
}

public class Test {
    public static void TestForPriority() {
        PriorityQueue<Card> p = new PriorityQueue<>();

        p.offer(new Card(1, "♥"));
        p.offer(new Card(2, "♥"));
    }

    public static void main(String[] args) {
        TestForPriority();
    }
}

运行结果为:

原因在上篇文中也有所提及,优先级队列底层使用堆,而向堆中插入元素中,为了满足堆的性质(offer方法中会检测是否有比较器,如果没有比较器会强转为Compareable),必须要进行元素的比较,而此时自定义类型Card是没有办法直接进行比较的,所以会抛出上面的异常。

2. 元素的比较

2.1 基本类型的比较

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

public class TestCompare {
    public static void main(String[] args) {
        int a = 10;
        int b = 20;
        System.out.println(a > b);
        System.out.println(a < b);
        System.out.println(a == b);
 
        char c1 = 'A';
        char c2 = 'B';
        System.out.println(c1 > c2);
        System.out.println(c1 < c2);
        System.out.println(c1 == c2);
 
        boolean b1 = true;
        boolean b2 = false;
        System.out.println(b1 == b2);
        System.out.println(b1 != b2);
    }
 }

2.2 对象比较的问题

代码如下

如果在main方法中

有System.out.println(c1 > c2),会编译报错

有System.out.println(c1 == c2) 编译成功 --> 打印false 因为c1和c2指向不是同一个对象

有System.out.println(c1 < c2) 会编译报错

有System.out.println(c1 == c3) 编译成功 --> 打印true 因为c1 和 c3指向的是同一个对象

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

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

下图为Object中equal的实现,可以看到:直接比较的是两个引用变量的地址

3. 对象的比较

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

3.1 覆写基类的equals方法

如图:在自定义类中重写equals方法

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

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

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

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

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

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

重写equals方法虽然可以进行比较,但缺点是:equal方法的返回值是boolean类型,只能按照相等的比较,不能按照大于,小于的方式进行比较

3.2 基于Comparable接口类的比较

Comparable是JDK提供的泛型的比较接口类,源码实现为:

public interface Comparable<E> {

        //返回值:

        // < 0:表示this指向的对象小于 o 指向的对象

        // > 0:表示this指向的对象大于 o 指向的对象

        // == 0: 表示this指向的对象等于 o 指向的对象

        int compareTo(E o);

}

对于用户自定义类型,如果要按照自己的方式进行比较时: 在定义类的时候,实现Comparable接口,然后在类中重写compareTo方法即可

如下图:根据数值进行比较,不管花色,这里认为null是最小的

测试符合预期:

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

3.3 基于比较器比较

具体实现步骤如下:

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

public interface Comparator<T> {

        // 返回值: // < 0: 表示 o1 指向的对象小于 o2 指向的对象

        // == 0: 表示 o1 指向的对象等于 o2 指向的对象

        // > 0: 表示 o1 指向的对象等于 o2 指向的对象

        int compare(T o1, T o2);

}

注意区分Comparable  和 Comparator

2.覆写Comparator中的compare方法

测试符合预期:

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

3.4 三种方式的对比

补充解释第二和第三种比较方式:

2. Comparable.comparaTo:

例如代码:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

class Employee implements Comparable<Employee> {
    private String name;
    private int age;

    public Employee(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public int compareTo(Employee other) {
        return Integer.compare(this.age, other.age);
    }

    public int getAge() {
        return age;
    }

    @Override
    public String toString() {
        return "Employee{name='" + name + "', age=" + age + "}";
    }
}

public class Main {
    public static void main(String[] args) {
        List<Employee> employees = new ArrayList<>();
        employees.add(new Employee("Alice", 25));
        employees.add(new Employee("Bob", 20));
        employees.add(new Employee("Charlie", 30));

        // 对员工列表进行排序
        Collections.sort(employees);

        for (Employee employee : employees) {
            System.out.println(employee);
        }
    }
}

2. Comparator.compare

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<Student> students = new ArrayList<>();
        students.add(new Student("Alice", 20));
        students.add(new Student("Bob", 18));
        students.add(new Student("Charlie", 22));

        // 创建比较器对象
        AgeComparator ageComparator = new AgeComparator();

        // 在排序算法中显式指定比较器
        Collections.sort(students, ageComparator);

        for (Student student : students) {
            System.out.println(student.getName() + " - " + student.getAge());
        }
    }
}

完!

相关文章:

  • 基于Weber和simulink的齿轮啮合刚度计算
  • 基于深度学习与知识图谱的设备智能维护系统KGPHMAgent
  • PHP2(WEB)
  • Redission可重试、超时续约的实现原理
  • C++:dfs,bfs各两则
  • kotlin的Int类型调用toString()会导致空指针吗
  • CountDownlatch实现原理
  • 1.2.2 AI 技术的融入
  • Linux 文件的三个时间:Access、Modify 和 Change
  • 【服务器与本地互传文件】远端服务器的Linux系统 和 本地Windows系统 互传文件
  • 对网络物理层芯片LAN8720A的复位信号(复位引脚nRST)的详细分析(顺便也介绍下其软复位的操作和导常情况解决方法)
  • AMBA-CHI协议详解(十八)
  • [论文解析]OmniRe: Omni Urban Scene Reconstruction
  • Java中的Stream API:从入门到实战
  • C#初级教程(5)——解锁 C# 变量的更多奥秘:从基础到进阶的深度指南
  • GPIO外设
  • Python数据类型 NoneType和唯一实例None
  • 25轻化工程研究生复试面试问题汇总 轻化工程专业知识问题很全! 轻化工程复试全流程攻略 轻化工程考研复试真题汇总
  • brew Nushell mac升级版本
  • npm使用了代理,但是代理软件已经关闭导致创建失败
  • 中国科学院院士、我国航天液体火箭技术专家朱森元逝世
  • 安徽省委常委、合肥市委书记费高云卸任副省长职务
  • 上海首发经济“卷”到会展业,浦东签约三个年度“首展”
  • 第二期人工智能能力建设研讨班在京开班,近40国和区域组织代表参加
  • 全国汽车以旧换新补贴申请量突破1000万份
  • 西藏日喀则市拉孜县发生5.5级地震,震感明显部分人被晃醒