Comparable和Comparator的区别

本文详细介绍了Java中Comparable和Comparator两个接口的区别与应用,通过实例演示了如何实现自定义类的排序规则,包括按照年龄、身高和体重等多条件排序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


一、Comparable与Comparator的相同点

Comparable和Comparator都是java的一个接口,多用于实现集合中元素的比较及排序。
当我们自定义一个类时,如果需要规定其中的排序规则时,我们就必须用到比较接口。例如:

public class Person{
    private String name;//姓名
    private int age;//年龄
    private double height;//身高
}

我们定义了一个类,想规定其按照年龄进行比较,并且将Person类的对象存在List集合中,调用集合工具类中的 Collections.sort 排序方法,这时不能得到我们想要得到的结果。而我们 String 却不然,如果我们讲 String 存入到List集合中,它会按照一定的顺序进行排序,因为我们String类中实现了 Comparable 接口,并重写了接口中的 compareTo 方法,如下:

public int compareTo(String anotherString) {
    int len1 = value.length;
    int len2 = anotherString.value.length;
    int lim = Math.min(len1, len2);
    char v1[] = value;
    char v2[] = anotherString.value;
    int k = 0;
    while (k < lim) {
        char c1 = v1[k];
        char c2 = v2[k];
        if (c1 != c2) {
            return c1 - c2;
        }
        k++;
    }
    return len1 - len2;
}

所以我们需要给自己定义的类定义一个比较的规则,我们就需要实现一个比较接口。

二、Comparable 和 Comparator 的区别

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4ME8kKGu-1661411237720)(/img/bVcPjFj)]

Comparable

Comparable 定义在想要实现排序对象的类的内部,并且重写compareTo方法,例如:

public class Person implements Comparable<Person>{
    private String name;//姓名
    private int age;//年龄
    private double height;//身高
    /**
     * 方法的作用就是定义比较规则
     * 返回值类型为int类型,取值范围分别为正数,负数,0
     * 正数:大于
     * 负数:小于
     * 0:等于
     * @param p
     * @return int
     */ 
     @Override
     public int compareTo(Person p) {
         return this.age - p.age;
     }
}

当一个类实现了Comparable接口并重写了CompareTo方法时,我们使用Collections.sort进行排序的话,会自动调用其自定义的比较规则进行比较排序,CompareTo方法的返回值为int类型,有三种情况,分别为:

1、自定义的比较规则中,比较着大于被比较者时,则返回正数;
2、自定义的比较规则中,比较着小于被比较者时,则返回负数;
3、自定义的比较规则中,比较着等于被比较者时,则返回0;

Comparator

Comparator 定义在想要实现排序对象的类的外部,并且重写compare方法。
当一个类未定义比较规则,并且我们想要对其进行排序时,会使用你匿名内部类的方式或者重新自定义一个类并实现Comparator接口的方式来达到这个目的,例如:
匿名内部类方式:

public class PersonTest {
    public static void main(String[] args) {
        Person p1 = new Person("张三", 18, 180);
        Person p2 = new Person("李四", 20, 165);
        Person p3 = new Person("王五", 15, 175);
        List<Person> list = new ArrayList();
        list.add(p1);
        list.add(p2);
        list.add(p3);
        Collections.sort(list, new Comparator<Person>() {
            @Override
            public int compare(Person o1, Person o2) {
                return o1.getAge()-o2.getAge();
            }
        });
        System.out.println(list);
 }
}

自定义类实现Comparator接口

public class PersonComparator implements Comparator<Person> {
    @Override
    public int compare(Person o1, Person o2) {
        return o1.getAge()-o2.getAge();
    }
}
public class PersonTest {
    public static void main(String[] args) {
        Person p1 = new Person("张三", 18, 180);
        Person p2 = new Person("李四", 20, 165);
        Person p3 = new Person("王五", 15, 175);
        List<Person> list = new ArrayList();
        list.add(p1);
        list.add(p2);
        list.add(p3);
        Collections.sort(list, new PersonComparator());
        System.out.println(list);
 }
}

其实,从原理上来讲它们没有什么太大的不同,都是实现了 Comparator 接口并重写了 Compare 方法,只是写法上有些区别。当然从复用性的角度来讲,还是自定义的复用性更高一些,这里还需要实际看需求决定。它的比较规则和上述的Comparable中的CompareTo方法一样, Compare 方法的返回值也为int类型,也有三种情况,分别为:

1、返回值类型为正数时,代表o1 > o2
2、返回值类型为负数时,代表o1 < o2
3、返回值类型为0时,代表o1 = o2

三、注意事项

无论是实现Comparable接口还是Comparator接口都需要指定泛型。

四、总结

实际上述两种方式各有利弊,实现Comparable使用比较简单,只要是实现了Comparable接口的类的对象,我们可以直接进行比较,但是在一些开发中我们开始未考虑到这里的情况下,想要改变就需要改变其源代码,不够方便;但是Comparator则不然,它可以在不修改源码的基础上,重新自定义一个比较器,这样降低了我们代码之间的耦合性,当我们之后想要改变一个比较算法时,也可以很方便的进行改变。我们只要重新定义一个比较规则即可。

五、课后作业

习题:
一个班内有5名学生,用java写一段代码,将学生们按照年龄从大到小排序,如果年龄一样则按身高排序(高到低),如果身高也一样,按体重排序(轻到重)。
答案:
Stu学生类

public class Stu implements Comparable<Stu>{
    private Integer id;
    private String name;
    private Integer age;
    private Integer height;//165cm
    private Integer weight;//51kg
    public Stu() {
    }
    public Stu(Integer id, String name, Integer age, Integer height, Integer weight) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.height = height;
        this.weight = weight;
    }
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    public Integer getHeight() {
        return height;
    }
    public void setHeight(Integer height) {
        this.height = height;
    }
    public Integer getWeight() {
        return weight;
    }
    public void setWeight(Integer weight) {
        this.weight = weight;
    }
    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", height=" + height +
                ", weight=" + weight +
                '}';
    }

    @Override
    public int compareTo(Stu o) {
        /*
            1.按年龄从大到小排序
            2.如果年龄一样则按照身高排序(高到低)
            3.如果身高一样则按照体重排序(轻到重)
         */
        if (age.compareTo(o.getAge())!=0)
            return o.getAge().compareTo(age);
        if (height.compareTo(o.getHeight())!=0)
            return o.getHeight().compareTo(height);
        return weight.compareTo(o.getWeight());
    }
}

StuTests学生测试类

public class StuTests {
    public static void main(String[] args) {
        List<Stu> list = new ArrayList<>();
        Stu stu1 = new Stu(1002,"tom",21,170,55);
        Stu stu2 = new Stu(1001,"tony",21,170,56);
        Stu stu3 = new Stu(1005,"amy",20,180,51);
        Stu stu4 = new Stu(1004,"jack",23,184,59);
        Stu stu5 = new Stu(1003,"rose",23,150,66);
        list.add(stu1);
        list.add(stu2);
        list.add(stu3);
        list.add(stu4);
        list.add(stu5);
        list.forEach(stu -> System.out.println(stu));
        /*
          Stu{id=1002, name='tom', age=21, height=170, weight=55}
          Stu{id=1001, name='tony', age=21, height=170, weight=56}
          Stu{id=1005, name='amy', age=20, height=180, weight=51}
          Stu{id=1004, name='jack', age=23, height=184, weight=59}
          Stu{id=1003, name='rose', age=23, height=150, weight=66}
         */
    }
}
### 回答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、付费专栏及课程。

余额充值