在阅读本文之前,建议读者有限阅读专栏内前面部分的文章

目录

前言

一、Java对象的比较:

二、PriorityQueue插入对象:

三、三种方法比较辨析:

总结


前言

本文主要介绍与Java的对象的比较相关的知识。


一、Java对象的比较:

我们在进行对象的比较的时候,有三种用来比较,分别是equals、comparable和comparator。其中,equals的返回值是布尔类型,故而只能够判断二者是否相同;而comparable和comparator返回值则是一个整型,所以是可以比较大小的。这两者的区别在于,comparable可以在当前类中使用,但是comparator是脱离当前类来使用。我们接下来分别来测试一下这几个方法:

class Card{
    public String suit;
    public int rank;

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

    @Override
    public String toString() {
        return "Card{" +
                "suit='" + suit + '\'' +
                ", rank=" + rank +
                '}';
    }
}
public class Test {
    public static void main(String[] args) {
        Card card1 = new Card("红桃", 5);
        Card card2 = new Card("红桃", 5);

        System.out.println(card1 == card2);
    }
}

上面代码运行结果如下:

这个原因很简单,上面这个比较其实就相当于在比较这两个的地址。地址不一样,最后返回肯定是false。那我们如何用equals方法呢?可不可以直接用下面这个代码:

System.out.println(card1.equals(card2));

这个代码运行结果如下:

这是因为其实我们在创建card类的时候是没有写equals方法的,所以它会调默认父类Object类的equals方法,而对于Object的equals方法来说,它的定义如下:

    public boolean equals(Object obj) {
        return (this == obj);
    }

所以和我们最开始的代码本质上是一样的。我们如果想要按照自己的方式去使用euals的话,就需要对这个方法进行重写。我们可以通过IDEA自动生成对应的equals()和hash(),代码如下:

import java.util.Objects;

class Card{
    public String suit;
    public int rank;

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

    @Override
    public String toString() {
        return "Card{" +
                "suit='" + suit + '\'' +
                ", rank=" + rank +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (o == null || getClass() != o.getClass()) return false;
        Card card = (Card) o;
        return rank == card.rank && Objects.equals(suit, card.suit);
    }

    @Override
    public int hashCode() {
        return Objects.hash(suit, rank);
    }
}
public class Test {
    public static void main(String[] args) {
        Card card1 = new Card("红桃", 5);
        Card card2 = new Card("红桃", 5);

        System.out.println(card1.equals(card2));
    }
}

这样的话,我们的运行结果如下:

所以说到这里我们是可以去比较两张牌是否相同的,但是两张牌的大小却没法比较得出。这个时候我们就需要调用comparable接口并且重写相关的方法。我的代码如下:

import java.util.Objects;

class Card implements Comparable<Card>{
    public String suit;
    public int rank;

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

    @Override
    public String toString() {
        return "Card{" +
                "suit='" + suit + '\'' +
                ", rank=" + rank +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (o == null || getClass() != o.getClass()) return false;
        Card card = (Card) o;
        return rank == card.rank && Objects.equals(suit, card.suit);
    }

    @Override
    public int hashCode() {
        return Objects.hash(suit, rank);
    }

    @Override
    public int compareTo(Card o) {
        return this.rank - o.rank;
    }
}
public class Test {
    public static void main(String[] args) {
        Card card1 = new Card("红桃", 5);
        Card card2 = new Card("黑桃", 10);
        if(card1.compareTo(card2) > 0){
            System.out.println("card1 > card2");
        }else{
            System.out.println("card1 <= card2");
        }

    }
}

这样的话,它的运行结果如下:

当然我们也可以利用comparator来根据花色比较大小,具体的操作就是首先我们要先创建一个类调用comparator接口,并且要重写其中的compare方法。然后在main方法中实例化一个比较器对象,进而实现二者的比较。我的代码如下:

import java.util.Comparator;
import java.util.Objects;

class Card implements Comparable<Card>{
    public String suit;
    public int rank;

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

    @Override
    public String toString() {
        return "Card{" +
                "suit='" + suit + '\'' +
                ", rank=" + rank +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (o == null || getClass() != o.getClass()) return false;
        Card card = (Card) o;
        return rank == card.rank && Objects.equals(suit, card.suit);
    }

    @Override
    public int hashCode() {
        return Objects.hash(suit, rank);
    }

    @Override
    public int compareTo(Card o) {
        return this.rank - o.rank;
    }
}

class SuitComparator implements Comparator<Card> {
    public int compare(Card o1, Card o2) {
        return o1.suit.compareTo(o2.suit);
    }
}

public class Test {
    public static void main(String[] args) {
        Card card1 = new Card("hongtao", 5);
        Card card2 = new Card("heitao", 10);
        if(card1.compareTo(card2) > 0){
            System.out.println("card1 > card2");
        }else{
            System.out.println("card1 <= card2");
        }
        System.out.println("==================");
        SuitComparator suitComparator = new SuitComparator();
        if(suitComparator.compare(card1, card2) == 0){
            System.out.println("card1 > card2");
        }else{
            System.out.println("card1 <= card2");
        }

    }
}

其运行结果如下:

二、PriorityQueue插入对象:

在上篇文章我们讲了优先级队列,优先级队列在插入元素时有个要求,插入的元素不能是null或者元素之间必须要能够进行比较。为了简单起见,我们只是插入了Integer类型。集合框架中的PriorityQueue底层使用堆结构,因此其内部的元素必须要能够比大小,PriorityQueue采用了
Comparble和Comparator两种方式。Comparble是默认的内部比较方式,如果用户插入自定义类型对象时,该类对象必须要实现Comparble接口,并覆写compareTo方法;用户也可以选择使用比较器对象,如果用户插入自定义类型对象时,必须要提供一个比较器类,让该类实现Comparator接口并覆写compare方法。具体的部分可以参考上面的内容和上篇文章。

三、三种方法比较辨析:

覆写的方法说明
Object.equals因为所有类都是继承自Object的,所以直接覆写即可,不过只能比较相等与否
Comparable.compareTo需要手动实现接口,侵入性比较强,但一旦实现,每次用该类都有顺序,属于内部顺序
Comparator.compare需要实现一个比较器对象,对待比较类的侵入性弱,但对算法代码实现侵入性强

总结

本文介绍了Java中对象比较的三种方法equals()、Comparable和Comparator。equals()用于判断对象是否相等,默认比较地址,需要重写;Comparable接口实现类内部比较,重写compareTo()方法;Comparator则是外部比较器,通过实现compare()方法实现灵活比较。文章通过扑克牌类Card的示例代码演示了三种方法的实际应用,并指出PriorityQueue要求元素必须可比较的特性。最后比较了三种方式的适用场景:equals是基础比较,Comparable提供默认顺序,Comparator实现灵活的外部比较规则。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐