Detailed explanation of sorting interface Comparable and comparator Comparator in Java

Comparisons of object arrays are often involved in Java. There are two common methods to deal with them:

  1. Natural sorting: inherit the comparable interface and implement the compareTo() method
  2. Customized sorting: Define a separate object comparator, inherit from the Comparator interface, and implement the compare() method

1. Comparable

1.1. Introduction to Comparable

Comparable is the sorting interface. ( Natural sorting )
If a class implements the Comparable interface, it means "this class supports sorting". Since the class that implements the Comparable interface supports sorting, assuming that there is now a "List (or array) of objects of the class that implements the Comparable interface", the List (or array) can be processed through Collections.sort (or Arrays.sort) Sort.
In addition, "objects of classes that implement the Comparable interface" can be used as keys in an "ordered map (such as a TreeMap)" or as elements in an "ordered set (TreeSet)" without specifying a comparator.

1.2. Typical implementation of Comparable: (by default, they are arranged from small to large)

1) String: Compare according to the Unicode value of the characters in the string
2) Character: Compare according to the Unicode value of the character
3) Packaging classes corresponding to numerical types and BigInteger, BigDecimal: Compare according to their corresponding numerical sizes
4) Boolean : The corresponding packaging class instance of true is greater than the corresponding packaging class instance of false
5) Date, Time, etc.: The later date and time are larger than the previous date and time

1.3. Comparable definition

The Comparable interface only includes one function, which is defined as follows:

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

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

Explanation: Suppose we use x.compareTo(y) to "compare the size of x and y". If a "negative number" is returned, it means "x is smaller than y"; if "zero" is returned, it means "x is equal to y"; if a "positive number" is returned, it means "x is greater than y".

Here, in order for everyone to better understand the Compareable interface, I hand-wrote a Compareable interface myself.

Case 1

Comparable interface

package com.company.strategy2;

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

    public int compareTo(T object);

}

Cat entity class

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 class (handwritten sorting algorithm, bubble sorting is used here)

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;
    }
}

Test class

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));
    }
}

In actual use, there is no need to write the Comparable interface and sort algorithm by hand.

Case 2:

Pig entity class

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 +
                '}';
    }
}

Test class

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));
    }
}

operation result 

2. Comparator

2.1. Introduction to Comparator 

1) When the element type does not implement the java.lang.Comparable interface and it is inconvenient to modify the code, or the sorting rules that implement the java.lang.Comparable interface are not suitable for the current operation, you can consider using Comparator objects to sort and force Compare multiple objects for overall sorting.
2) Rewrite the compare(Object o1, Object o2) method to compare the sizes of o1 and o2: if the method returns a positive integer, it means that o1 is greater than o2; if it returns 0, it means they are equal; if it returns a negative integer, it means that o1 is less than o2.
3) A Comparator can be passed to the sort method (such as Collections.sort or Arrays.sort), allowing precise control over the sort order.
4) You can also use Comparator to control the order of certain data structures (such as ordered sets or ordered maps), or to provide sorting for object collections that have no natural order.

2.2. Comparator definition

The Comparator interface only includes two functions, which are defined as follows:

package java.util;

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

    boolean equals(Object obj);
}

Explanation: If a class wants to implement the Comparator interface: it must implement the compareTo(T o1, T o2) function, but it does not need to implement the equals(Object obj) function.

Question: Why can't we implement the equals(Object obj) function?

Because any class has implemented equals(Object obj) by default. All classes in Java inherit from java.lang.Object, and the equals(Object obj) function is implemented in Object.java; therefore, all other classes are equivalent to implementing this function.

int compare(T o1, T o2) is "compare the sizes of o1 and o2". Returning "negative number" means "o1 is smaller than o2"; returning "zero" means "o1 is equal to o2"; returning "positive number" means "o1 is greater than o2"

Similarly, for everyone to understand more intuitively, I will also write two cases here, one is a handwritten Comparator interface, and the other is using the Comparator interface provided by java.

Case 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 entity class

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;
    }
}

Comparator class for 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;
        }
    }
}

sort sorting method in sorting class Sorter

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;
    }
}

Test class

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));
    }
}

You can also use test class Lambda expressions to write here

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));
    }
}

Case 2:

Dog entity class

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's Comparator Class 

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;
        }
    }
}

Test class

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));

    }
}

operation result 

3. Comparator and Comparable comparison

Comparable is a sorting interface: If a class implements the Comparable interface, it means "this class supports sorting".

Comparator is a comparator: if we need to control the order of a certain class, we can create a "comparator of this class" for sorting.

It is not difficult for us to find that Comparable is equivalent to "internal comparator", and Comparator is equivalent to "external comparator".
 

Guess you like

Origin blog.csdn.net/m0_50370837/article/details/126207399