ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Comparable和Comparator接口的差异

2021-06-10 19:32:19  阅读:203  来源: 互联网

标签:Comparable Comparator 对象 接口 比较 rank println public Card


Comparable和Comparator接口

问题提出

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

//定义扑克牌内部类
class Card{
    public int rank;  //代表牌的数值
    public String suit; //代表牌的花色

    public Card(int rank, String suit) {
        this.rank = rank;
        this.suit = suit;
    }
}
public class TestDemo {
    public static void main(String[] args) {
        fun();
    }

    public static void fun(){
        PriorityQueue<Card> priorityQueue = new PriorityQueue<>();
        //将Card对象加入优先级队列
        priorityQueue.offer(new Card(1,"♥"));
        priorityQueue.offer(new Card(2,"♣"));
    }
}

来看一下main执行结果:

在这里插入图片描述
程序抛出了类型不兼容引发的运行时异常,也就是说

这是无法实现的,为了满足堆的性质,必须进行元素的比较,而Card类型对象是无法进行比较的,因此抛出异常。

引用类型对象比较

基本数据类型比较

在Java语言中,基本数据类型可以直接比较大小

public static void main(String[] args) {
        //整型
        int a = 66;
        int b = 88;
        System.out.println(a > b);
        System.out.println(a == b);
        System.out.println(a < b);
        //字符型
        char c = 'A';
        char d = 'B';
        System.out.println(c > d);
        System.out.println(c == d);
        System.out.println(c < d);
        //布尔型
        boolean e = true;
        boolean f = false;
        System.out.println(e == f);
        System.out.println(e != f);
    }

在这里插入图片描述

对象的比较

先看一段代码

在这里插入图片描述
可以看出对Card类型对象按 < 或者 > 方式进行比较时,编译会出错,也就说明引用类型变量是无法进行大小比较的;
在这里插入图片描述
在这里插入图片描述
但是我们发现,使用==却没有编译报错,这是因为Java中规定所有类都默认继承父类Object,而Object类提供了equals方法,默认情况下==调用的是equals方法,该方法的比较规则是:不比较对象的内容,直接比较对象的第地址。c1和c3指向的是同一对象,所以比较结果为true。

那么如何比较对象的内容?大致三种方式:重写equals、实现Comparable接口、实现Comparator接口

1.重写equals方法

@Override
    public boolean equals(Object obj) {
        //重写equals
        if(this == obj){
            return true;
        }
        
        //obj为null或者obj不是Card子类对象
        if(obj == null || obj instanceof Card){
            return false;
        }
        
        //基本数据类型可以直接比较,引用类型最好还是调用equals
        Card c = (Card)obj;
        return rank == c.rank && suit.equals(c.suit);
    }

缺点:只能以相等的方式进行比较,不能按照大于、小于的方式对对象进行比较。

2.Comparable接口

看一下java.lang.Comparable接口源码,在这个接口中,只存在一个抽象方法compareTo:
在这里插入图片描述在这里插入图片描述

定义方法返回值为int,源码定义的比较规则:
< 0:表示this指向的对象小于o指向的对象
== 0:表示this指向的对象等于o指向的对象
0:表示this指向的对象大于o指向的对象

知道了源码中怎么设置比较大小规则后,对于我们自定义的类型而言,如果要按照大小方式进行比较,让自定义的类实现Comparable接口并重写compareTo方法。

class Card implements Comparable<Card>{
    public int rank;  //代表牌的数值
    public String suit; //代表牌的花色

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

    //根据牌的数值比较,不管牌的花色,认为null对象是最小的
    @Override
    public int compareTo(Card o) {
        if(o == null){
            return 1;
        }else{
            return rank - o.rank;
        }
    }
}
public class TestDemo {

    public static void main(String[] args) {
        Card a = new Card(1,"♠");
        Card b = new Card(2,"♦");
        Card c = new Card(1,"♥");
        System.out.println(a.compareTo(b)); 
        System.out.println(a.compareTo(c));
        System.out.println(b.compareTo(c));
    }
}

在这里插入图片描述
从执行结果可以看出,此时我们就可以比较对象之间的大小了

3.Comparator接口

按照Comparator接口进行对象之间的比较,具体步骤如下:

先看一下java.util.Comparator接口源码
在这里插入图片描述
在这里插入图片描述

定义方法返回值为int,源码定义的比较规则:
< 0:表示o1指向的对象小于o2指向的对象
== 0:表示o1指向的对象等于o2指向的对象
0:表示o1指向的对象大于o2指向的对象

我们可以通过一个自定义类比较器去实现Comparator接口,通过比较器类中compare方法进行对象之间的大小比较。

/**
 * 自定义类
 */
class Card{
    public int rank;  //代表牌的数值
    public String suit; //代表牌的花色

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

/**
 * 比较器类
 */
class CardComparator implements Comparator<Card>{
    //我们根据牌的数值去比较大小,不管花色
    @Override
    public int compare(Card o1, Card o2) {
        if(o1 == o2) return 0;
        if(o1 == null) return -1;
        if(o2 == null) return 1;
        return o1.rank - o2.rank;
    }
}

public class TestDemo {
    public static void main(String[] args) {
        Card p = new Card(1,"♣");
        Card q = new Card(2,"♦");
        Card o = new Card(1,"♥");

        //定义比较器对象
        CardComparator cardComparator = new CardComparator();
        
        //使用比较器对象进行比较
        System.out.println(cardComparator.compare(q,p));
        System.out.println(cardComparator.compare(p,o));
        System.out.println(cardComparator.compare(o,q));
    }

}

在这里插入图片描述
通过实现Comparator接口也完成了对象之间大小比较。

三者的区别

equals:默认所有类都是继承Object类的,因此直接在自定义类中重写该方法就行,但是只能比较两个对象相等与否,不能比较对象大小关系。

compareTo:在自定义类手动实现Comparable接口,侵入性极强,一旦实现,后面使用该类都有顺序。

compare:与实现Comparable接口不同的是,需要额外定义一个比较器类实现Comparator接口,在比较器类中重写compare方法,最后创建比较器类对象去实现自定义类对象之间的大小比较;对待自定义类的侵入性弱,但对算法代码实现侵入性强。

标签:Comparable,Comparator,对象,接口,比较,rank,println,public,Card
来源: https://blog.csdn.net/weixin_44874269/article/details/117767344

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有