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

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排序算法.

案例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接口:它一定要实现compareTo(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接口

案例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:

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相当于“外部比较器”。
 

猜你喜欢

转载自blog.csdn.net/m0_50370837/article/details/126207399