Comparable比较器和Comparator比较器

目录

为什么需要比较器

Comparable比较器

Camparator比较器

Comparable比较器和Camparator比较器的区别


为什么需要比较器

对于基本数据类型,可以使用:

  • ==
  • !=
  • >
  • <

来比较两个基本数据类型的大小关系,得到的结论可以是

  • 相等
  • 不相等
  • 大于
  • 小于

中间的任何一个。这四个运算符的存在,足够支持开发者进行排序操作了。

但是,如果是两个对象的内容进行比较呢?

首先比较的是内容,肯定不能使用上面的四个运算符,因为两个对象使用运算符进行运算时,比较的是两个对象在堆中的地址而不是两个对象的具体内容,因此使用上面四个运算符是必然无法进行两个对象内容的比较的。

此时,在java中便存在一个比较器,可以使用比较器对两个对象进行排序,从而对对象内容的关系进行判断(大于、小于、等于)。

存在了比较器之后,便可以直接调用比较器对内容进行判断,从而可以很方便的实现多个对象的排序。


在java中,提供了两种比较器:

  1. Comparable比较器,存在于java.lang软件包中,进行的是两个对象内容之间的自然排序,即只能对对象进行单纯的升序排序和降序排序。
  2. Camparator比较器,存在于java.util软件包中,这个比较器允许进行自定义排序。(例如对对象的某一个关键字进行升序排序,而当这个关键字的值相同时,再根据另一个关键字进行降序排序)。



Comparable比较器

在Comparable接口中,只有一个抽象方法:

 既然比较器比较的是两个对象内容的大小关系,那么此时便可以随便找一个引用数据类型观察一下其对compareTo方法的重写,此处以String类为例:

阅读完该方法的描述后,可以知道:

  • 该方法只有一个形参,名为anotherString,表示需要和当前字符串进行比较的字符串。
  • 该方法的返回值有三种:大于零的整数、小于零的整数、0。
  • 在对字符串进行比较时,每次比较的是两个字符串对应位置(描述为第k个位置)的Unicode编码值,并且是使用当前字符串第k个位置字符的Unicode编码值减去anotherString字符串第k个位置字符Unicode编码值,因此会得到一个整数,这个整数只会存在三种情况:大于零、小于零、等于零,正好对应了该方法的三种返回值。
  • 若是两个字符串的长度不相等,那么便返回当前字符串和anotherString字符串长度的差值,即当前字符串的长度减去anotherString字符串的长度,同样会得到一个整数,这个整数同样也只会存在三种情况:大于零、小于零、等于零,正好对应了该方法的三种返回值。

由此看来,使用compareTo(String)方法是可以得到两个字符串的大小关系。

下面便来测试一下:

public class Test {
    public static void main(String[] args) {
        String str1 = "1234abcd";
        String str2 = "1234abcd";
        String str3 = "1234ab";

        System.out.println("str1 compare str2 = " + str1.compareTo(str2));
        System.out.println("str1 compare str3 = " + str1.compareTo(str3));
        System.out.println("str2 compare str3 = " + str2.compareTo(str3));
        System.out.println("str3 compare str2 = " + str3.compareTo(str2));

    }
}

得到的结果为:

可以看到,和之前分析的结果一致,当两个串相等时,返回0;当当前字符串的长度和形参字符串的长度不相等时,返回的是当前字符串的长度和形参字符串长度之差,即this.length()-anotherString.length()。


上面的compareTo()方法是在已有的类中已经重写好的,如果在自己定义的类中,实现compareTo()比较器,那该如何实现呢?

下面来看一个栗子:

public class class1 implements Comparable<class1> {
    private int num1;

    public void setNum1(int num1) {
        this.num1 = num1;
    }

    /**
     * 如果当前对象的num1值大于比较对象的num1值,返回一个正数;
     * <p>
     * 如果当前对象的num1值小于比较对象的num1值,返回一个负数;
     * <p>
     * 如果当前对象的num1值等于比较对象的num1值,返回一个0;
     *
     * 那么,在排序中,返回值为正数则表示降序排序;返回值为负数则表示升序排序
     **/
    @Override
    public int compareTo(class1 o) {
        return this.num1 - o.num1;
    }
}

 在class1类中,实现了compareTo比较器。

下面对这个比较器进行测试:

public class Test {
    public static void main(String[] args) {
        class1 c1 = new class1();
        class1 c2 = new class1();

        c1.setNum1(1);
        c2.setNum1(2);

        System.out.println(c1.compareTo(c2));
        System.out.println(c2.compareTo(c1));
    }
}

测试结果为:

可以看到,当对象c1和对象c2使用比较器进行比较时,返回了一个负值,表示对象c1是小于对象c2的;当对象c2和对象c1使用比较器进行比较时,返回了一个正值,表示对象c2是大于对象c1的。




Camparator比较器

可以看到,Camparable比较器只能对两个对象中的单一关键字进行比较,但在现实中,还存在许多需要对多个关键字进行比较的场合,此时便可以使用Camparator比较器进行多关键字比较,或者说是自定义排序规则的比较。

既然是自定义排序规则,那么便需要对已有的排序规则进行重写。

下面来看一个自定义排序的栗子:

有一个名为Goods的类,类中含有构造器,set和get方法以及重写了一个toString()方法

public class Goods {
    private String GoodsName;
    private int GoodPrice;

    public Goods() {
    }

    public Goods(String name, int price) {
        this.GoodPrice = price;
        this.GoodsName = name;
    }

    public String getGoodsName() {
        return GoodsName;
    }

    public void setGoodsName(String goodsName) {
        GoodsName = goodsName;
    }

    public int getGoodPrice() {
        return GoodPrice;
    }

    public void setGoodPrice(int goodPrice) {
        GoodPrice = goodPrice;
    }

    @Override
    public String toString() {
        return "Goods{" +
                "GoodsName='" + GoodsName + '\'' +
                ", GoodPrice=" + GoodPrice +
                '}' + '\n';
    }
    
}

下面对这个类的对象进行排序:

import java.util.Arrays;
import java.util.Comparator;

public class Test {
    public static void main(String[] args) {
        Goods[] goods = {new Goods("bread", 6), new Goods("milk", 2), new Goods("cola", 3), new Goods("bread", 15)};

        //按照名称进行升序排序,如果名称相同,则按照价格进行降序排序
        Arrays.sort(goods, new Comparator<Goods>() {
            @Override
            public int compare(Goods o1, Goods o2) {
                if (o1.getGoodsName().equals(o2.getGoodsName())) {
                    return o2.getGoodPrice() - o1.getGoodPrice();
                } else {
                    return o1.getGoodsName().compareTo(o2.getGoodsName());
                }
            }
        });

        System.out.println(Arrays.toString(goods));
    }
}

可以看到,此时重写了Arrays类的sort()方法,实现了Comparator接口中的compare方法,该方法的效果是:按照名称对goods对象中的数据进行升序排序,如果名称相同,那么便对goods对象中名称相同的数据进行降序排序。

程序的运行结果为:




Comparable比较器和Camparator比较器的区别

Comparable比较器只能比较仅含有单个关键字的对象,因此仅适用于对单个关键字进行排序,而Camparator比较器作为Comparable比较器性能不足的弥补,可以允许自定义比较规则,因而可以用于多个关键字的排序。

两个比较器结合使用可以十分灵活地进行对象的排序。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值