Java中的排序接口Comparable和比较器Comparator详解

在java中经常涉及到对象数组的比较的情况,常见的有两种方法来处理:

  1. 自然排序: 继承comparable接口,并实现compareTo()方法
  2. 定制排序: 定义一个单独的对象比较器,继承自Comparator接口,实现compare()方法

一、Comparable

1.1、Comparable简介

Comparable 是排序接口。(自然排序)
若一个类实现了Comparable接口,就意味着“该类支持排序”。 即然实现Comparable接口的类支持排序,假设现在存在“实现Comparable接口的类的对象的List列表(或数组)”,则该List列表(或数组)可以通过 Collections.sort(或 Arrays.sort)进行排序。
此外,“实现Comparable接口的类的对象”可以用作“有序映射(如TreeMap)”中的键或“有序集合(TreeSet)”中的元素,而不需要指定比较器。

1.2、Comparable 的典型实现:(默认都是从小到大排列的)

1)String:按照字符串中字符的Unicode值进行比较
2)Character:按照字符的Unicode值来进行比较
3)数值类型对应的包装类以及BigInteger、BigDecimal:按照它们对应的数值大小进行比较
4)Boolean:true 对应的包装类实例大于 false 对应的包装类实例
5)Date、Time等:后面的日期时间比前面的日期时间大

1.3、Comparable 定义

Comparable 接口仅仅只包括一个函数,它的定义如下:

package java.lang;
import java.util.*;

public interface Comparable {
    public int compareTo(T o);
}

解释: 假设我们通过 x.compareTo(y) 来“比较x和y的大小”。若返回“负数”,意味着“x比y小”;返回“零”,意味着“x等于y”;返回“正数”,意味着“x大于y”。

这里为了大家更好的理解Compareable这个接口, 我自己手写了一个Compareable接口.

1.3.1、案例1

Comparable接口

package com.company.strategy2;

/**
 * Created by 苍狼
 * Time on 2022-08-06
 */
public interface Comparable<T> {

    public int compareTo(T object);

}

Cat实体类

package com.company.strategy2;

/**
 * Created by 苍狼
 * Time on 2022-08-06
 */
public class Cat implements Comparable<Cat> {

    private int height;

    private int weight;

    public Cat(int height, int weight){
        this.height = height;
        this.weight = weight;
    }

    public int compareTo(Cat cat){
        if(this.height>cat.height){
            return 1;
        } else if(this.height<cat.height){
            return -1;
        } else{
            return 0;
        }
    }


    @Override
    public String toString() {
        return "Cat{" +
                "height=" + height +
                ", weight=" + weight +
                '}';
    }

}

Sorter类(手写排序算法, 这里用到的是冒泡排序)

package com.company.strategy2;

/**
 * Created by 苍狼
 * Time on 2022-08-06
 */
public class Sorter {

    public static void sort(Comparable[] arr) {
        if (arr == null || arr.length < 2) {
            return;
        }
        for (int e = arr.length - 1; e > 0; e--) {
            for (int i = 0; i < e; i++) {
                if (arr[i].compareTo(arr[i + 1]) == 1) {
                    swap(arr, i, i + 1);
                }
            }
        }
    }

    public static void swap(Comparable[] arr, int i, int j) {
        Comparable temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}

测试类

package com.company.strategy2;

import java.util.Arrays;

public class Main {

    public static void main(String[] args) {
        Cat[] cats = {new Cat(111,111), new Cat(555,555), new Cat(222,222), new Cat(444,444)};
        Sorter sorter = new Sorter();
        sorter.sort(cats);
        System.out.println(Arrays.toString(cats));
    }
}

实际使用中则不需要自己手写Comparable接口和sort排序算法.

1.3.2、案例2

Pig实体类

package com.company.strategy2;

/**
 * Created by 苍狼
 * Time on 2022-08-07
 */
public class Pig implements java.lang.Comparable<Pig> {

    private Double weight;

    public Pig(Double weight){
        this.weight = weight;
    }

    @Override
    public int compareTo(Pig pig) {
        if (this.weight>pig.weight) {
            return 1;
        } else if (this.weight<pig.weight){
            return -1;
        } else {
            return 0;
        }
    }

    @Override
    public String toString() {
        return "Pig{" +
                "weight=" + weight +
                '}';
    }
}

测试类

package com.company.strategy2;

import java.util.Arrays;

/**
 * Created by 苍狼
 * Time on 2022-08-07
 */
public class Test {

    public static void main(String[] args) {
        Pig[] pigs = new Pig[]{new Pig(123.5), new Pig(145.6), new Pig(111.6)};
        System.out.println(Arrays.toString(pigs));

        Arrays.sort(pigs);

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

运行结果 

二、Comparator

2.1、Comparator简介 

1) 当元素的类型没有实现java.lang.Comparable接口而又不方便修改代码,或者实现了java.lang.Comparable接口的排序规则不适合当前的操作,那么可以考虑使用 Comparator 的对象来排序,强行对多个对象进行整体排序的比较。
2) 重写compare(Object o1,Object o2)方法,比较o1和o2的大小:如果方法返回正整数,则表示o1大于o2;如果返回0,表示相等;返回负整数,表示o1小于o2。
3) 可以将 Comparator 传递给 sort 方法(如 Collections.sort 或 Arrays.sort),从而允许在排序顺序上实现精确控制。
4) 还可以使用 Comparator 来控制某些数据结构(如有序 set或有序映射)的顺序,或者为那些没有自然顺序的对象 collection 提供排序。

2.2、Comparator定义

Comparator 接口仅仅只包括两个个函数,它的定义如下:

package java.util;

public interface Comparator {
    
    int compare(T o1, T o2);

    boolean equals(Object obj);
}

解释: 若一个类要实现Comparator接口:它一定要实现compare(T o1, T o2) 函数,但可以不实现 equals(Object obj) 函数。

问题: 为什么可以不实现 equals(Object obj) 函数呢?

因为任何类,默认都是已经实现了equals(Object obj)的。 Java中的一切类都是继承于java.lang.Object,在Object.java中实现了equals(Object obj)函数;所以,其它所有的类也相当于都实现了该函数。

int compare(T o1, T o2) 是“比较o1和o2的大小”。返回“负数”,意味着“o1比o2小”;返回“零”,意味着“o1等于o2”;返回“正数”,意味着“o1大于o2”

同样的, 为了大家更加直观的理解, 我这里也同样写两个案例, 一个手写Comparator接口, 一个使用java提供的Comparator接口

2.2.1、案例1

package com.company.strategy3;

/**
 * Created by 苍狼
 * Time on 2022-08-06
 */

@FunctionalInterface //如果这里只有一个方法, 则这个也可以不写
public interface Comparator<T> {

    public int compare(T t1, T t2);

    default void show(){
        System.out.println("世界, 你好....");
    }

}


Cat实体类

package com.company.strategy3;

/**
 * Created by 苍狼
 * Time on 2022-08-06
 */
public class Cat{

    private int height;

    private int weight;

    public Cat(int height, int weight){
        this.height = height;
        this.weight = weight;
    }
    
    @Override
    public String toString() {
        return "Cat{" +
                "height=" + height +
                ", weight=" + weight +
                '}';
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public int getWeight() {
        return weight;
    }

    public void setWeight(int weight) {
        this.weight = weight;
    }
}

cat的比较器类

package com.company.strategy3;

/**
 * Created by 苍狼
 * Time on 2022-08-06
 */
public class CatComparator implements Comparator<Cat>{

    @Override
    public int compare(Cat t1, Cat t2) {
        if(t1.getHeight()*t1.getWeight()>t2.getHeight()*t2.getWeight()){
            return 1;
        } else if (t1.getHeight()*t1.getWeight()<t2.getHeight()*t2.getWeight()){
            return -1;
        } else{
            return 0;
        }
    }
}

排序类Sorter中的sort排序方法

package com.company.strategy3;

/**
 * Created by 苍狼
 * Time on 2022-08-06
 */
public class Sorter<T> {

    public void sort(T[] arr, Comparator<T> comparator) {
        if (arr == null || arr.length < 2) {
            return;
        }
        for (int e = arr.length - 1; e > 0; e--) {
            for (int i = 0; i < e; i++) {
                if (comparator.compare(arr[i], arr[i+1])==1){
                    swap(arr, i, i+1);
                }
            }
        }
    }

    public void swap(T[] arr, int i, int j) {
        T temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}

测试类

package com.company.strategy3;

import java.util.Arrays;

public class Main {

    public static void main(String[] args) {
        Cat[] cats = {new Cat(111,111), new Cat(555,555), new Cat(222,222), new Cat(444,444)};
        Sorter<Cat> sorter1 = new Sorter<>();
        sorter1.sort(cats, new CatComparator());
        System.out.println(Arrays.toString(cats));
    }
}

这里也可以用测试类Lambda表达式来写

package com.company.strategy3;

import java.util.Arrays;

public class Main {

    public static void main(String[] args) {
        Sorter sorter = new Sorter();
        Cat[] cats= new Cat[]{new Cat(1111,1111), new Cat(8888,8888), new Cat(3333,3333), new Cat(6666,6666)};
        sorter.sort(cats, (o1,o2)->{
            if (o1.getHeight()>o2.getHeight()){
                return 1;
            } else if (o1.getHeight()<o2.getHeight()){
                return -1;
            } else{
                return 0;
            }
        });

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

2.2.2、案例2

Dog实体类

package com.company.strategy3;

/**
 * Created by 苍狼
 * Time on 2022-08-06
 */
public class Dog implements Comparable<Dog> {

    private int food;

    public Dog(int food){
        this.food = food;
    }

    @Override
    public int compareTo(Dog dog) {
        if(this.food > dog.food){
            return 1;
        } else if (this.food < dog.food){
            return -1;
        } else{
            return 0;
        }
    }

    @Override
    public String toString() {
        return "Dog{" +
                "food=" + food +
                '}';
    }

    public void setFood(int food){
        this.food = food;
    }

    public int getFood(){
        return this.food;
    }
}

Dog的比较器类 

package com.company.strategy3;

/**
 * Created by 苍狼
 * Time on 2022-08-06
 */
public class DogComparator implements Comparator<Dog>{

    @Override
    public int compare(Dog t1, Dog t2) {
        if (t1.getFood()>t2.getFood()){
            return 1;
        } else if (t1.getFood()<t2.getFood()){
            return -1;
        } else{
            return 0;
        }
    }
}

测试类

package com.company.strategy3;

import java.util.Arrays;

/**
 * Created by 苍狼
 * Time on 2022-08-07
 */
public class Test {

    public static void main(String[] args) {
        Dog[] dogs = new Dog[]{new Dog(111), new Dog(777), new Dog(555), new Dog(333)};
        System.out.println(Arrays.toString(dogs));

        System.out.println("=====================");

        Arrays.sort(dogs, new DogComparator());
        System.out.println(Arrays.toString(dogs));

    }
}

运行结果 

Comparator 和 Comparable比较

Comparable是排序接口: 若一个类实现了Comparable接口,就意味着“该类支持排序”。

而Comparator是比较器: 我们若需要控制某个类的次序,可以建立一个“该类的比较器”来进行排序。

我们不难发现:Comparable相当于“内部比较器”,而Comparator相当于“外部比较器”。
 

  • 9
    点赞
  • 65
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
JavaComparableComparator都是用于进行对象比较的接口。它们的用法如下: 1. Comparable接口 Comparable接口Java内置的接口,它包含一个方法compareTo(),用于比较对象的大小。实现该接口的类可以直接进行排序。 例如,我们定义一个Person类实现Comparable接口: ``` public class Person implements Comparable<Person> { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } public int compareTo(Person person) { // 按照年龄进行排序 return this.age - person.age; } } ``` 在这个例子,我们通过实现Comparable接口,并重写compareTo()方法,按照年龄进行排序。 使用Comparable接口进行排序的例子: ``` List<Person> list = new ArrayList<Person>(); list.add(new Person("Tom", 20)); list.add(new Person("Jerry", 18)); list.add(new Person("Jack", 25)); Collections.sort(list); for(Person p : list) { System.out.println(p.getName() + " " + p.getAge()); } ``` 输出结果: ``` Jerry 18 Tom 20 Jack 25 ``` 2. Comparator接口 Comparator接口也是Java内置的接口,它包含一个方法compare(),用于比较两个对象的大小。实现该接口的类可以定制不同的比较规则。 例如,我们定义一个PersonComparator类实现Comparator接口: ``` public class PersonComparator implements Comparator<Person> { public int compare(Person p1, Person p2) { // 按照姓名进行排序 return p1.getName().compareTo(p2.getName()); } } ``` 在这个例子,我们通过实现Comparator接口,并重写compare()方法,按照姓名进行排序。 使用Comparator接口进行排序的例子: ``` List<Person> list = new ArrayList<Person>(); list.add(new Person("Tom", 20)); list.add(new Person("Jerry", 18)); list.add(new Person("Jack", 25)); Collections.sort(list, new PersonComparator()); for(Person p : list) { System.out.println(p.getName() + " " + p.getAge()); } ``` 输出结果: ``` Jack 25 Jerry 18 Tom 20 ``` 总之,ComparableComparator都是用于对象比较的接口。使用Comparable接口可以方便地对实现该接口的对象进行排序,而使用Comparator接口可以定制不同的比较规则。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值