Analysis and difference between Comparable and Comparator

preface

In learning, we often use the List collection and Array to operate a certain number of element objects, and the Collections collection tool class contains some static methods to sort, exchange, find and other operations of the collection. This paper mainly describes the two implementation methods of Comparable and Comparator. Therefore, only in terms of sorting, most basic data type source codes implement the Comparable interface and rewrite the compareTo method. For custom type objects, if the Comparable or Comparator interface is not implemented, sorting cannot be carried out.
String implements the comparable interface and rewrites the compareTo method as follows:

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence 

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;
        //Each character of the string is compared here. If it is equal, the next character is compared, and if it is not equal, it is returned.
        while (k < lim) {
            char c1 = v1[k];
            char c2 = v2[k];
            if (c1 != c2) {
                return c1 - c2;
            }
            k++;
        }
        return len1 - len2;
    }

1, Comparable

1. General

Comparable translates to sortable, which means that it supports sorting function. It is an internal implementation method, also known as natural sorting. All basic data types implement this interface to sort, and user-defined classes implement this interface, and the user-defined class will automatically have the ability to sort. Generally, sorting is implemented when customizing classes, and the sorting rules are specified. The source code must be modified every time the sorting rules are modified. Generally, it is not recommended to modify the source code in this way to change the sorting rules. If you need to modify sorting rules, you can implement a specific sorting method externally by implementing Comparator.

2.Comparable instance

Student class:

package Test;

/**
 * @author Fox
 * @date 2021/11/26 14:30
 */
public class Student implements Comparable<Student>{
    private int num;//Student number
    private String name;//full name
    private int age;//Age
    private int socre;//achievement

    public Student() {
    }

    public Student(int num, String name, int age,int socre) {
        this.num = num;
        this.name = name;
        this.age = age;
        this.socre = socre;
    }

    @Override
    public String toString() {
        return "Student{" +
                "num=" + num +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", socre=" + socre +
                '}';
    }
    /**
     * Sort by student number
     * @param o
     * @return
     */
    @Override
    public int compareTo(Student o) {
        int result = 0;
        //The first implementation @@@@@@@@@@@@@@@@@@@@@@@@@@@ tag 1
        result = this.socre - o.socre;
        //The second implementation @@@@@@@@@@@@@@@@@@@@@@@@@@@@ tag 2
        //result = o.score - this.score;
        if (result == 0)
        	//If the scores here are equal, call the compareTo method of the string name to sort the equal items
            return this.name.compareTo(o.name);
        return result;
    }
}

Comparable_test class:

package Test;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;

/**
 * @author Fox
 * @date 2021/11/26 14:30
 */
public class Comparable_test {
    public static void main(String[] args) {
        ArrayList<Student> list = new ArrayList<>();
        list.add(new Student(1,"fox",20,88));
        list.add(new Student(2,"fox1",20,94));
        list.add(new Student(3,"fox2",20,91));
        list.add(new Student(4,"fox3",20,85));
        list.add(new Student(4,"fox4",20,88));

        Collections.sort(list);

        for (Student student : list) {
            System.out.println(student);
        }

    }
}

The result of the first implementation tag 1:

The result of the second implementation tag 2:

Note: the above two result diagrams show that there are two objects with 88 scores, because I implemented two sorting rules when implementing the Comparable interface. After the same element appears, I will sort again according to other attributes. Where Student{num=1, name='fox', age=20, socre=88}
Student{num=4, name='fox4', age=20, socre=88}
Is comparing the results of sorting.

3. Key points

  • 1. Using collections.sort to sort is actually calling the method of Array.sort.
  • 2. Many people don't know the difference and function between positive and negative and zero of the return value of comparaTo method. In fact, I don't know it here. I read many blogs saying that moling is ambiguous. Finally, I learned a simple method to judge ascending and descending order by asking professional teachers. If you subtract the incoming object from the current object, the result is in ascending order regardless of the result value, such as return len1 - len2; And result = this.socre - o.socre; If the object of the current caller is subtracted from the incoming object, it is represented as descending order. For example, result = o.score - this.score; The results in ascending and descending order are shown in the figure marked one and two above.
    (I haven't figured out the difference between the return values, which may be related to the internal sorting algorithm of Array.sort)
  • 3. This method has advantages and disadvantages to implement the Comparable interface. The advantage is that we can customize the sorting rules and sort according to those attributes (for example, in the above code, sort the score scores first, and then use the name string to compare and sort if the same ones appear). A certain disadvantage is that if the amount of code is large after writing the code, we need to change the drawing of the sorting rules, A lot of source code needs to be modified. If the interface is implemented and the compareTo method is rewritten, it is generally not recommended to use this method for modification.

2, Comparator

1. General

Comparator represents a comparator. The object of the class that implements the interface is a comparator defined for the object of the target class. Generally, this comparator will be passed as a parameter to the Collections.sort and Arrays.sort methods to specify the sorting method of a class object. It is generally called external implementation.
If the Comparable interface is not implemented or the existing sorting does not meet the existing sorting requirements, the Comparator can be used to implement it.
Comparator embodies a strategy design pattern, which uses a strategy object to change its behavior without changing the object itself.

2.Comparator instance

1. For the case where Comparable has been implemented above (the implemented sorting does not meet the existing sorting requirements)

The Student class is not displayed. There are on it.
Comparator_test class:

/**
 * @author Fox
 * @date 2021/11/26 14:30
 */
public class Comparable_test {
    public static void main(String[] args) {
        ArrayList<Student> list = new ArrayList<>();
        list.add(new Student(1,"fox",20,88));
        list.add(new Student(2,"fox1",20,94));
        list.add(new Student(3,"fox2",20,91));
        list.add(new Student(4,"fox3",20,85));
        list.add(new Student(4,"fox4",20,88));
        Collections.sort(list, new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                int result = o1.getSocre() - o2.getSocre();
                if (result == 0)
                    return o1.getNum() - o2.getNum();
                return result;
            }
        });
        for (Student student : list) {
            System.out.println(student);
        }

    }
}

The results are as follows:

Note: at this time, the external comparator is used to realize the new sorting. If the scores are equal, compare and sort by comparing the num student number attribute as follows.
Student{num=1, name='fox', age=20, socre=88}
Student{num=4, name='fox4', age=20, socre=88}

2. The user-defined object does not implement the Comparable interface.

Student class:

/**
 * @author Fox
 * @date 2021/11/26 14:30
 */
public class Student {
    private int num;//Student number
    private String name;//full name
    private int age;//Age
    private int socre;//achievement

    public Student() {
    }

    public Student(int num, String name, int age, int socre) {
        this.num = num;
        this.name = name;
        this.age = age;
        this.socre = socre;
    }

    public int getNum() {
        return num;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public int getSocre() {
        return socre;
    }

    @Override
    public String toString() {
        return "Student{" +
                "num=" + num +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", socre=" + socre +
                '}';
    }
    
}

Comparator_test class:

/**
 * @author Fox
 * @date 2021/11/26 16:16
 */
public class Comparator_test {
    public static void main(String[] args) {
        ArrayList<Test.Student> list = new ArrayList<>();
        list.add(new Test.Student(1,"fox",20,88));
        list.add(new Test.Student(2,"fox1",20,94));
        list.add(new Test.Student(3,"fox2",20,91));
        list.add(new Test.Student(4,"fox3",20,85));
        list.add(new Test.Student(4,"fox4",20,88));
        //lambada expressions are used here
        Collections.sort(list, (o1, o2) -> {
        	//The latter object minus the former object is flashback
            int result = o2.getSocre() - o1.getSocre();
            if (result == 0)
            	//If the same occurs, let Num use ascending order
                return o1.getNum() - o2.getNum();
            return result;
        });
        for (Student student : list) {
            System.out.println(student);
        }

    }
}

The results are as follows:

Note: the ascending order of score and descending order of num are used here.

3. Key points

  • Like the Comparable method above, subtracting the former object from the latter object can be understood as ascending, and subtracting the latter object from the former object can be understood as descending.
  • The passed Comparator parameter is implemented by an anonymous inner class and overrides the compare method.
  • Comparator embodies a strategy design pattern, which uses a strategy object to change its behavior without changing the object itself.

summary

This paper is only the author's rough understanding of the two methods in the learning process. What makes people headache is the difference and role of return value in the process of set sorting (not clear). The revolution has not been successful, and comrades still need to work hard. If there is any mistake, please correct it.

Keywords: Java Algorithm set

Added by mighty on Fri, 26 Nov 2021 22:05:09 +0200