比较器: Comparable 与 Comparator 区别

比较器: Comparable 与 Comparator 区别

在这里插入图片描述


每博一文案

师父说: 人不能精得过火,太精明的人往往让人生厌,人也别傻的可怜,一腔热血付出却白忙一场。
太精明的人,凡事都想要争个明明白白,每一分钱都要和人计较。把便宜占尽,把好事包揽,
时间长了,即使再好的朋友也会离去,过于精明就成了算计,成了小肚鸡肠,没有人原意和这样的人相处。
太老实的人,更容易被别人欺负,对人付出要看值不值得,你的付出是否会得到他的回应。
帮助别人要看自己能力,做不到的事情就不要勉强自己。别为了面子委屈自己,
拒绝总比敷衍和拖延来的更好,别惯坏了得寸进尺的人,把你的付出当成理所当然,
别纵容了不知感恩的心,把你的好意当成傻子嬉戏。
对你好的人,要加倍珍惜,把你冷的人,要趁早远离,别精地过火,也别傻得可怜,
做人做事,无愧于心就好。 
                                  ——————   一禅心灵庙语


在Java中经常会涉及到对象数组的排序问题,那么就涉及到对象之间的比较问题。

  • Java实现对象排序的方式有两种:

  • 自然排序: java.lang.Comparable

  • 定制排序: java.util.Comparator

1. 自然排序:java.lang.Comparable

  • Comparable 的典型实现 (默认都是从小到大排序)

在这里插入图片描述

  • String : 按照字符串中字符的 Unicode 值进行比较。
  • Character : 按照字符的 Unicode 值进行比较。
  • 数值类型对应的包装类以及 Biglnteger,BigDecimal ,按照它们对应的数值大小进行比较。默认是升序(从小到大) 排序的。
  • Boolean: true 对应的包装类实例大于 false 对应的包装类实例。
  • Date,Time 等: 后面的日期时间比前面的日期时间大。
  • Comparable j接口强行对实现它的每个类的对象进行整体排序,这种排序被称为 类排序
  • 实现 Comparable 的类必须实现 其中的 compareTo(object obj) 方法,两个对象即通过 comparTo(Object obj) 方法的返回值来比较大小。
  • 在这里插入图片描述

在这里插入图片描述

  • 默认是升序:比较的规则是:
    • 如果当前对象 this > 形参对象 obj ,则返回正整数。
    • 如果当前对象 this < 形参对象obj ,则返回负整数。
    • 如果当前对象 this == 形参对象 obj,则返回 0
  • 实现 Comparable 接口的对象列表(和数组),可以通过 Collections.sort()Arrays.sort() 进行排序,实现此接口的对象可以用作,有序映射中的键或有序集合中的元素,无需指定 比较器。
  • 比如: 对于 类 C 的每一个 e1 和 e2 来说,当且仅当 e1.comparTo(e2) == 0e1.equals(e2) ,具有相同的 boolean 值时,类 C的自然排序才叫做 equals 一致,建议(虽然不是必需的) 最好使 自然排序 与 equals 一致。
  • 说明:
    • Java 中的对象,正常情况下,只能进行比较,== 或 != ,不能使用 >< 的,但是在开发场景中,我们需要对多个对象进行排序,言外之意,就需要比较对象的大小。如何实现 ??? 使用 实现 两个接口中的任何一个 ComparableComparato

举例: 使用 Arrays 中的 sort 排序

import java.util.Arrays;

public class Comparable {
    public static void main(String[] args) {
        String[] arr = {"AA","CC","BB","FF","DD","EE"};
        // 排序前:
        System.out.println(Arrays.toString(arr));
        // 排序后:
        Arrays.sort(arr);  // 排序默认是(升序)
        System.out.println(Arrays.toString(arr));

    }
}

在这里插入图片描述

举例: 自定义一个商品类,属性:String name(商品名),double price(商品的价格) ,通过商品的价格进行升序排序。

  • String ,包装类实现了 Comparable 接口,并重写 compareTo() 方法,给出了比较两个对象大小。
    • 重写 compareTo() 的规则:
      • 如果当前对象this > 形参对象Obj,则返回正整数。
      • 如果当前对象 this < 形参对象 Obj,则返回负整数,
      • 如果当前对象 this == 形参对象 Obj,则返回 0
  • 在定义类来说,如果需要排序,我们可以让自定义类实现 Comparable 接口,重写 compartTo() 在compareTo(obj) 方法中指明
    如何排序的。

在这里插入图片描述

自定义类 implements Comparable 实现该接口,并重写了其中的 compareTo()抽象方法 后就可以比较了。

import java.util.Arrays;


class Commodity implements Comparable {
    String name;
    double price;

    public Commodity() {
        // 无参构造器
    }

    public Commodity(String name, double price) {
        this.name = name;
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    @Override
    public int compareTo(Object o) {
        /**
         * 比较规则:
         * * 如果当前对象this > 形参对象Obj,则返回正整数。
         * * 如果当前对象 this < 形参对象 Obj,则返回负整数,
         * * 如果当前对象 this == 形参对象 Obj,则返回。
         */
        // 1. 首先判断该类,是否是 Commodity 的实例,不是就不用比较了,类都不一样
        if (o instanceof Commodity) {
            // 2.强制转换为对应的 Commodity 的实例对象,获取到其中的比较值
            Commodity commodity = (Commodity) o;

            if(this.price > commodity.price) {
                return 1;
            } else if(this.price < commodity.price) {
                return -1;
            } else {
                return 0;   // 两个对象比较的值相等。
            }

        }
        // 抛出运行异常
        throw new RuntimeException("传入的数据类型不一致");
    }

    @Override
    public String toString() {
        return "Commodity{" +
                "name='" + name + '\'' +
                ", price=" + price +
                '}';
    }
}


public class ComparableTest {
    public static void main(String[] args) {
        Commodity[] commodities = new Commodity[5];
        commodities[0] = new Commodity("lenovoMouse", 34);
        commodities[1] = new Commodity("dellMouse", 43);
        commodities[2] = new Commodity("xiaoMouse", 12);
        commodities[3] = new Commodity("huaweiMouse", 65);
        commodities[4] = new Commodity("roogyao", 35);

        Arrays.sort(commodities);

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

在这里插入图片描述


修改重写: compareTo() 的比较规则,根据商品的价格进行降序排序

规则:

  • 如果当前对象this < 形参对象Obj,则返回正整数。
  • 如果当前对象 this > 形参对象 Obj,则返回负整数,
  • 如果当前对象 this == 形参对象 Obj,则返回 0
import java.util.Arrays;


class Commodity implements Comparable {
    String name;
    double price;

    public Commodity() {
        // 无参构造器
    }

    public Commodity(String name, double price) {
        this.name = name;
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    @Override
    public int compareTo(Object o) {
        /**
         * 比较规则:
         * * 如果当前对象this > 形参对象Obj,则返回正整数。
         * * 如果当前对象 this < 形参对象 Obj,则返回负整数,
         * * 如果当前对象 this == 形参对象 Obj,则返回。
         */
        // 1. 首先判断该类,是否是 Commodity 的实例,不是就不用比较了,类都不一样
        if (o instanceof Commodity) {
            // 2.强制转换为对应的 Commodity 的实例对象,获取到其中的比较值
            Commodity commodity = (Commodity) o;

            if(this.price > commodity.price) {
                return -1;
            } else if(this.price < commodity.price) {
                return 1;
            } else {
                return 0;   // 两个对象比较的值相等。
            }

        }
         // 抛出运行异常
        throw new RuntimeException("传入的数据类型不一致");
    }

    @Override
    public String toString() {
        return "Commodity{" +
                "name='" + name + '\'' +
                ", price=" + price +
                '}';
    }
}


public class ComparableTest {
    public static void main(String[] args) {
        Commodity[] commodities = new Commodity[5];
        commodities[0] = new Commodity("lenovoMouse", 34);
        commodities[1] = new Commodity("dellMouse", 43);
        commodities[2] = new Commodity("xiaoMouse", 12);
        commodities[3] = new Commodity("huaweiMouse", 65);
        commodities[4] = new Commodity("roogyao", 35);

        Arrays.sort(commodities);

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

在这里插入图片描述


升级需求:

先对商品的价格进行升序排序,如果商品的价格是一样的,就对其中的商品名进行二次降序排序。

import java.util.Arrays;


class Commodity implements Comparable {
    String name;
    double price;

    public Commodity() {
        // 无参构造器
    }

    public Commodity(String name, double price) {
        this.name = name;
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }


    @Override
    public String toString() {
        return "Commodity{" +
                "name='" + name + '\'' +
                ", price=" + price +
                '}';
    }

    @Override
    public int compareTo(Object o) {
        /**
         * 比较规则:
         * * 如果当前对象this > 形参对象Obj,则返回正整数。
         * * 如果当前对象 this < 形参对象 Obj,则返回负整数,
         * * 如果当前对象 this == 形参对象 Obj,则返回。
         */
        // 1. 首先判断该类,是否是 Commodity 的实例,不是就不用比较了,类都不一样
        if (o instanceof Commodity) {
            // 2.强制转换为对应的 Commodity 的实例对象,获取到其中的比较值
            Commodity commodity = (Commodity) o;
            if (this.price > commodity.price) {
                return -1;
            } else if (this.price < commodity.price) {
                return 1;
            } else {
                // 对于价格相同的商品,对商品名进行“降序” 二次排序
                // 这里我们直接调用 String 类型中已经重写好的 compareTo()方法就进行排序
                return this.name.compareTo(commodity.name);  // compareTo()默认就是 “升序”
            }

        }
        throw new RuntimeException("传入的数据类型不一致");
    }

}


public class ComparableTest {
    public static void main(String[] args) {
        Commodity[] commodities = new Commodity[5];
        commodities[0] = new Commodity("lenovoMouse", 34);
        commodities[1] = new Commodity("dellMouse", 34);
        commodities[2] = new Commodity("xiaoMouse", 12);
        commodities[3] = new Commodity("huaweiMouse", 65);
        commodities[4] = new Commodity("roogyao", 65);

        Arrays.sort(commodities);

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

在这里插入图片描述

解析:

return -this.name.compareTo(commodity.name);

为什么填一个 "-" 符号

这里我们直接调用 String 类型中已经重写好的 compareTo()方法就进行排序

这里我们 附加一个 "-1"负数的意思是:compareTo()默认就是 “升序”

升序: this > 参数对象,返回正整数,this < 参数对象,返回负整数

降序: this > 参数对象,返回负整数, this < 参数对象,返回正整数

这两者的结果刚好相反:所以:我们将升序的返回结果 填一个 “-” 负号就变成了:降序

同理:将降序的返回结果,填一个 - 负号,就变成了:升序


2. 定制排序:java.util.Comparator

在这里插入图片描述

  • 当元素的类型没有实现 java.lang.Comparable 接口而又不方便修改代码,或者实现了java.lang.Comparable 接口的排序不合适当前的操作,那么可以考虑使用 Comparator 的对象来排序,强行对多个地下进行整体排序的比较。
  • 重写compare(Object o1, Object o2) 方法,比较规则和: Comparable() 是一样的。

在这里插入图片描述

在这里插入图片描述

  • 升序的:比较规则:
    • 如果当前对象 this > 形参对象 obj ,则返回正整数。
    • 如果当前对象 this < 形参对象obj ,则返回负整数。
    • 如果当前对象 this == 形参对象 obj,则返回 0
  • 可以将 Comparato 传递给 sort() 方法,如 (Collections.sort)Arrays.sort) ,从而允许在排序顺序上实现精度控制。
  • 还可以使用 Comparator 来控制某些数据结构 (如有序 set 或有序映射)的顺序,或者为那些没有自然顺序的对象的 collection 提供排序。
  • 一般对于 Comparator的使用都是一次性的,所以一般都是使用匿名的方式

举例: 对 String 数组中的内容进行 降序排序

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

public class ComparatorTest {
    public static void main(String[] args) {
        String[] arr = {"AA", "CC", "DD", "GG", "EE", "FF", "DD", "ZZ"};

        // 排序前
        System.out.println(Arrays.toString(arr));

        // 通过匿名实现 Comparator 接口,并重写其中的 compare()抽象方法
        Arrays.sort(arr, new Comparator() {

            // 重写 compare()抽象方法,降序
            @Override
            public int compare(Object o1, Object o2) {
                // 1. 首先判断:是否是比较的对象的类型
                if (o1 instanceof String && o2 instanceof String) {
                    // 2. 强制转换为对于的实例对象,获取到比较的值
                    String s1 = (String) o1;
                    String s2 = (String) o2;

                    // 3. 这里我们调用 String 已经重写好的 compareTo()方法,默认是升序
                    // 这里我们附加上一个 '-' 负号变成,降序
                    return -s1.compareTo(s2);
                }
                // 异常可以代替 return 返回值
                throw new RuntimeException("比较类型不一致");
            }
        });

        // 排序后的结果:
        System.out.println(Arrays.toString(arr));
    }
}

在这里插入图片描述


3. Comparable 与 Comparator 的区别

  • Comparable 和 Comparator 都是接口。都有定义好的比较的抽象方法 , Comparable 的是 comparTo() ,Comparator 的是compare()
  • Comparable 的是 comparTo() 是一个参数,比较的是 this 当前对象 与 参数对象的比较
  • Comparator 的是compare(Object o1 , Object o2) 的是两个参数,比较的是 参数 o1 对象 与 参数 o2对象的比较
  • Comparable 中的 comparTo()的抽象方法已经被大部分 类已经重写了,我们是不可以修改的,比如 String ,Doubel 类就已经重写了 comparTo()抽象方法,并且 String 是被 final 修饰的是无法继承,再重写 comparTo()抽象方法的,就导致 String 中的 comparTo()一直只能时默认的升序了 ,当我们要对 String 类型的数据进行降序 排序时,就无法实现了。这时候,我们就可以通过 重写 Comparator 的是compare()抽象方法,定制自己所需要的排序规则 时降序,还是升序了。
  • 一般对于 Comparator的使用都是一次性的,所以一般都是使用匿名的方式
Arrays.sort(arr, new Comparator() {

            // 重写 compare()抽象方法,降序
            @Override
            public int compare(Object o1, Object o2) {
                // 1. 首先判断:是否是比较的对象的类型
                if (o1 instanceof String && o2 instanceof String) {
                    // 2. 强制转换为对于的实例对象,获取到比较的值
                    String s1 = (String) o1;
                    String s2 = (String) o2;

                    // 3. 这里我们调用 String 已经重写好的 compareTo()方法,默认是升序
                    // 这里我们附加上一个 '-' 负号变成,降序
                    return -s1.compareTo(s2);
                }
                // 异常可以代替 return 返回值
                throw new RuntimeException("比较类型不一致");
            }
        });

4. 总结:

  • 自然排序的当我们想对自定的类,进行排序时可以重写 Comparable 接口中的 int compareTo(T o) 抽象方法,默认一些已经实现 Comparable 接口的并重写了 compareTo()抽象方法,String,Doubel,Arrays 默认时升序的。
  • 升序的规则:
    • 如果当前对象this > 形参对象Obj,则返回正整数。
    • 如果当前对象 this < 形参对象 Obj,则返回负整数,
    • 如果当前对象 this == 形参对象 Obj,则返回 0
  • 降序则是相反的:
    • 如果当前对象this < 形参对象Obj,则返回正整数。
    • 如果当前对象 this > 形参对象 Obj,则返回负整数,
    • 如果当前对象 this == 形参对象 Obj,则返回 0
  • 升序和降序的刚好是相反的,将升序的返回结果 填一个 “-” 负号就变成了:降序同理:将降序的返回结果,填一个 - 负号,就变成了:升序。
  • 当 Comparable 接口中的抽象方法的排序,无法满足我们的时候,我们可以实现 Comparator 接口中的 int compare(T o1,T o2) 定制自己需要的排序规则
  • 一般对于 Comparator的使用都是一次性的,所以一般都是使用匿名的方式

5. 最后:

限于自身水平,其中存在的错误,希望大家给予指教,韩信点兵——多多益善,谢谢大家,江湖再见,后会有期 !!!


在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: "Comparable" 和 "Comparator" 这两个词在 Java 编程语言中都是用于排序的概念。 - "Comparable" 是 Java 类库自带的一个接口,它的实现类可以使用 Java 内置的排序方法,例如 Collections.sort()。如果一个类实现了 "Comparable" 接口,就表示这个类支持比较排序。 - "Comparator" 是一个独立的接口,它的实现类可以用于定义自定义的排序方法,例如 Collections.sort(List, Comparator)。如果某个类没有实现 "Comparable" 接口,那么可以通过使用 "Comparator" 来实现排序。 总的来说,如果一个类已经实现了 "Comparable" 接口,那么可以直接使用它的比较方法进行排序。如果没有实现,则需要使用 "Comparator" 来定义自定义的排序方法。 ### 回答2: ComparableComparator是在Java中用于比较对象的两种不同方式。 1. Comparable是一个接口,它允许与它相关的类实现自己的比较规则。实现Comparable接口的类必须实现compareTo()方法,该方法用于定义对象之间的自然排序。compareTo()方法返回一个整数值,表示当前对象与参数对象的比较结果。这个值决定了两个对象之间的大小关系。 2. Comparator是一个接口,它允许在不修改源代码的情况下定义一个额外的比较规则。与Comparable不同,实现Comparator接口的类可以独立于被比较的类进行比较。Comparator接口要求实现compare()方法,该方法用于定义两个参数对象之间的比较结果。compare()方法返回一个整数值,表示对象之间的大小关系。 因此,Comparable是被实现在对象自身内部的排序规则,而Comparator是一个独立的外部排序规则。利用Comparable实现的排序规则是类内部默认的排序规则,而Comparator通过传入不同的比较器来实现多种排序规则。 在使用场景上,Comparable常用于对已有的类进行排序,而Comparator通常用于对现有的类进行定制化的排序需求。 ### 回答3: ComparableComparator都是Java中用于排序的接口,它们主要的区别在于使用的方式和对象类型。 Comparable接口是Java中的一个泛型接口,它定义了一个compareTo()方法,用于比较当前对象和另一个对象的大小。实现Comparable接口的类可以直接通过compareTo()方法进行比较和排序,例如,使用Collections.sort()方法对Comparable对象进行排序。 Comparator接口也是Java中的一个泛型接口,它定义了一个compare()方法,用于比较两个对象的大小。Comparator接口是一个独立于被比较的对象的比较器,可以用于实现灵活的比较逻辑。比如,如果一个类已经实现了Comparable接口,但我们想要根据不同的条件进行排序,就可以使用Comparator接口来定义不同的比较器Comparator接口可以作为参数传递给排序方法,如Collections.sort(),来实现定制的排序。 简而言之,Comparable是一个类的内部排序方式,实现Comparable接口的类可以通过compareTo()方法进行大小比较和排序。Comparator是一个独立的比较器,可以用于比较任意类型的对象,通过compare()方法来实现不同的排序逻辑。相比之下,Comparator的灵活性更高,可以用于实现各种不同的排序规则和策略,而Comparable只能用于同一种排序逻辑的对象。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值