Java custom classes implement the sorting of specified rules: Comparator interface, Comparable interface, CompareTo(), Compare()

1. The basic steps of sorting

  • Implementation method 1: Implement the Comparable interface without using a comparator
    1.Implement the java.lang.Comparable interface
    2、Override the compareTo(Object obj) method, pay attention to using this (current element) to compare with obj, single parameter.
    3. The key point is the return value of the compareTo() method. The return value is very important, so it stipulates the sorting rules

  • Implementation method 2: use a comparator: implement the Comparator interface
    1, implement the comparator implement the java.util.Comparator interface.
    2. Implement the compare(Object o1, Object o2) method, and formulate comparison rules.
    3. Often pass the Comparator to the required parts (such as the construction method of TreeSet, Arrays.sort (sorted content, comparator))

Note: How to choose Comparable and Comparator?
1. When the comparison rules will not change, or when there is only one comparison rule, it is recommended to implement the Comparable interface.
2. If there are multiple comparison rules and frequent switching between multiple comparison rules is required, it is recommended to use the Comparator interface.

  • Note: Some common classes have implemented the Comparable interface such as: String, Integer, Date...can be sorted directly
    insert image description here

2. Example: Sort custom classes (specify comparison rules yourself)

  • If the custom class wants to sort, it needs to implement the Comparable interface, otherwise, the downcast will fail when sorting! (You can look at the source code and know when the put method of map is used)
    insert image description here

2.1. Implementation of Method 1:

1、实现java.lang.Comparable接口
2、重写compareTo(Object obj)方法,注意使用this(当前元素)和obj进行比较
3、重点是compareTo()这个方法的返回值,返回值很重要,就规定了排序的规则
  • Code implementation:
    first in ascending order of age, and then in ascending order of name if the ages are the same.
/*
先按照年龄升序,如果年龄一样的再按照姓名升序。
 */
public class TreeSetTest05 {
    
    
    public static void main(String[] args) {
    
    
        TreeSet<Vip> vips = new TreeSet<>();
        vips.add(new Vip("zhangsi", 20));
        vips.add(new Vip("zhangsan", 20));
        vips.add(new Vip("king", 18));
        vips.add(new Vip("soft", 17));
        for(Vip vip : vips){
    
    
            System.out.println(vip);
        }
    }
}
class Vip implements Comparable<Vip>{
    
    
    String name;
    int age;

    public Vip(String name, int age) {
    
    
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
    
    
        return "Vip{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    /*
    compareTo方法的返回值很重要:
        返回0表示相同,value会覆盖。
        返回>0,会继续在右子树上找。【10 - 9 = 1 ,1 > 0的说明左边这个数字比较大。所以在右子树上找。】
        返回<0,会继续在左子树上找。
     */
    @Override
    public int compareTo(Vip v) {
    
    
        // 写排序规则,按照什么进行比较。
        if(this.age == v.age){
    
    
            // 年龄相同时按照名字排序。
            // 姓名是String类型,可以直接比。调用compareTo来完成比较。
            return this.name.compareTo(v.name);
        } else {
    
    
            // 年龄不一样
            return this.age - v.age;
        }
    }

2.2 Implementation of Method 2:

  • Steps: use the comparator: implement the Comparator interface
    1, implement the comparator implement the java.util.Comparator interface.
    2. Implement the compare(Object o1, Object o2) method, and formulate comparison rules.
    3. Often pass the Comparator to the required parts (such as the construction method of TreeSet, Arrays.sort (sorted content, comparator))

  • Turtle's Age Comparison Example

import java.util.Comparator;
import java.util.TreeSet;
/*
TreeSet集合中元素可排序的第二种方式:使用比较器的方式。
最终的结论:
    放到TreeSet或者TreeMap集合key部分的元素要想做到排序,包括两种方式:
        第一种:放在集合中的元素实现java.lang.Comparable接口。
        第二种:在构造TreeSet或者TreeMap集合的时候给它传一个比较器对象。
Comparable和Comparator怎么选择呢?
    当比较规则不会发生改变的时候,或者说当比较规则只有1个的时候,建议实现Comparable接口。
    如果比较规则有多个,并且需要多个比较规则之间频繁切换,建议使用Comparator接口。

    Comparator接口的设计符合OCP原则。
 */
public class TreeSetTest06 {
    
    
    public static void main(String[] args) {
    
    
        // 创建TreeSet集合的时候,需要使用这个比较器。
        // TreeSet<WuGui> wuGuis = new TreeSet<>();//这样不行,没有通过构造方法传递一个比较器进去。

        // 给构造方法传递一个比较器。
        //TreeSet<WuGui> wuGuis = new TreeSet<>(new WuGuiComparator());

        // 大家可以使用匿名内部类的方式(这个类没有名字。直接new接口。)
        TreeSet<WuGui> wuGuis = new TreeSet<>(new Comparator<WuGui>() {
    
    
            @Override
            public int compare(WuGui o1, WuGui o2) {
    
    
                return o1.age - o2.age;
            }
        });

        wuGuis.add(new WuGui(1000));
        wuGuis.add(new WuGui(800));
        wuGuis.add(new WuGui(810));

        for(WuGui wuGui : wuGuis){
    
    
            System.out.println(wuGui);
        }
    }
}

// 乌龟
class WuGui{
    
    
    int age;
    public WuGui(int age){
    
    
        this.age = age;
    }
    @Override
    public String toString() {
    
    
        return "小乌龟[" +
                "age=" + age +
                ']';
    }
}
// 单独在这里编写一个比较器
// 比较器实现java.util.Comparator接口。(Comparable是java.lang包下的。Comparator是java.util包下的。)
/*
class WuGuiComparator implements Comparator<WuGui> {
    @Override
    public int compare(WuGui o1, WuGui o2) {
        // 指定比较规则
        // 按照年龄排序
        return o1.age - o2.age;
    }
}
 */
  • Example of sorting a two-dimensional array
int[][] people = {
    
    {
    
    7,0},{
    
    4,4},{
    
    7,1},{
    
    5,0},{
    
    6,1},{
    
    5,2}};
Arrays.sort(people, new Comparator<int[]>() {
    
    
    public int compare(int[] o1, int[] o2) {
    
    
        if (o1[0] == o2[0]) return o1[1] - o2[1];//如果想让h相同k小的站前面,多这一行!
        return o2[0]-o1[0];//o1本来就已经是数组中的每个元素,再o1[]就是该元素内部的东西再指定一次
    }
});

//输出
for(int[] data : people){
    
    
     System.out.println(Arrays.toString(data));
 }

输出结果:
[7, 0]
[7, 1]
[6, 1]
[5, 0]
[5, 2]
[4, 4]

3. Precautions

3.1 The basic data types can only be sorted directly, and the sorting rules cannot be customized (stream flow operations can be used)

  1. Note that to change the default sort order,Cannot use basic types (int, double, char) but use their corresponding wrapper classes, such as the following will report an error. Change the array to Integer[] ints = new Integer[]{12, 4, 6, 7, 2, 8, 3, 9};so that the data will not report an error.
  2. Please be aware of,int is a basic data type, and int[] is not a basic data type! ! ! Therefore, in the use of generic types such as map collections, int[] can be written directly, and Integer[] cannot be written.
    insert image description here
  3. Arrays.sort() implements ascending order by default, if you want to change it to descending order, Arrays.sort(排序数组, Collections.reverseOrder());you can do it like this.
  4. Check the source code to know that there are eight overloaded data types including Object, and the other seven are basic types: int , long , short , char , byte , float , double. For custom types, you must specify the comparison rules yourself , for basic data types, there are implementations by default.

3.2 Use stream to implement custom sorting for basic data types

	int nums = {
    
    1,-5,-4,36,5,-9,4,-8,15};
    	// 将数组按照绝对值大小从大到小排序,注意要按照绝对值的大小
	nums = IntStream.of(nums) //IntStream是一种特殊的Stream,用来提供对int类型数据进行相关的stream操作
		     .boxed() //装箱,变为Stream<Integer>
		     .sorted((o1, o2) -> Math.abs(o2) - Math.abs(o1)) //操作封装的数据类型。使用lambda表达式
		     .mapToInt(Integer::intValue)//返回一个 IntStream,其中包含将给定函数应用于此流的元素的结果。
		     .toArray(); //IntStream转为数组

3.3 Connect to the first point above. Convert int[] to Integer[]

Here, the java8 stream is used for conversion. The detailed steps are as follows:

//初始化int数组
int[] nums = {
    
    1,2,3,4,5,6};
//将int数组转换为数值流
IntStream stream = Arrays.stream(nums);
//流中的元素全部装箱,转换为Integer流 
Stream<Integer> integerStream = stream.boxed();
//将流转换为数组
Integer[] integers = integerStream.toArray(Integer[]::new);

The above is the decomposition step, which can be solved by one line of code in actual application

Integer newNums[] = Arrays.stream(nums).boxed().toArray(Integer[]::new);

Guess you like

Origin blog.csdn.net/YiGeiGiaoGiao/article/details/129276949