# 比较器Comparator

在Java中，如果想要对对象进行排序，一般有两种方式：

* 待比较对象的类实现Comparable接口，重写compareTo(T o)方法（一般称之为自然排序）
* 自定义Comparator，重写Compare(T o1, T o2)方法（一般称之为定制排序）

## **Comparable**

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

* 对实现Comparable接口的类的对象的List/数组，则该List/数组可以通过Collections.sort/ Arrays.sort进行排序。
* 对实现Comparable接口的类的对象，可以用作有序键值对容器(如TreeMap)中的键或有序集合(如TreeSet)中的元素，而不需要指定比较器。

它的定义如下：

```java
public interface Comparable<T> {
    public int compareTo(T o);
}
```

compareTo(T o)的返回结果的说明：假设我们通过 x.compareTo(y) 来“比较x和y的大小”。

* 若返回“负数”，意味着“x比y小”
* 返回“零”，意味着“x等于y”
* 返回“正数”，意味着“x大于y”

## **Comparator**

Comparator的定义如下：

```java
public interface Comparator<T> {

    int compare(T o1, T o2);

    boolean equals(Object obj);
}
```

说明：

* 若一个类实现Comparator接口，则必须要实现compareTo(T o1, T o2) 函数，但可以不实现 equals(Object obj) 函数。

> 为什么可以不实现 equals(Object obj) ： Java中的一切类都是继承于java.lang.Object，在Object.java中实现了equals(Object obj)函数，所以，其它所有的类也相当于都实现了该函数。即任何类默认都是已经实现了equals(Object obj)的。

* compare(T o1, T o2) 的返回结果的说明：

  * 返回“负数”，意味着“o1比o2小”；

  * 返回“零”，意味着“o1等于o2”；

  * 返回“正数”，意味着“o1大于o2”。

  > 注意：**JDK1.7中，必须返回一对相反数，如1和-1，不能是1和0。因为1.7的排序算法采用**[**TimSort**](https://baike.baidu.com/item/TimSort)**，对返回值有严格要求**

无论对于Comparable还是Comparator，都有这样一个推荐做法：

```java
(compare(x, y)==0) ==  x.equals(y)
x.compare(y) == x.equals(y)
```

即两个对象通过compare比较等于0， 则最好这两个对象是equals的。反之，如果两个对象通过compare比较不相等，那么这两个对象通过equals比较时，返回fasle。

## 使用

待排序的对象的类

```java
public class Person implements Comparable<Person>{

    private String name;

    private int age;

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

    @Override
    public int compareTo(Person o) {
        int res = 0;
        if(age > o.age){
            res = 1;
        }else if(age < o.age){
            res = -1;
        }
        return res;
    }

    @Override
    public String toString() {
        return String.format("%s: %d", this.name, this.age);
    }

    //省略getter和setter方法
}
```

排序

```java
public class Example {

    public static void main(String[] args) {

        //初始化对象集合
        List<Person> personList = new ArrayList<>();
        personList.add(new Person("a", 18));
        personList.add(new Person("aa", 6));
        personList.add(new Person("aaa", 32));
        personList.add(new Person("aaaa", 21));

        System.out.println("默认按年龄排序");
        Collections.sort(personList);
        personList.forEach(person -> {
            System.out.println(person);
        });


        System.out.println("自定义按名字的长度排序");
        Collections.sort(personList, new Comparator<Person>() {
            @Override
            public int compare(Person o1, Person o2) {
                int length1 = o1.getName().length();
                int length2 = o2.getName().length();
                int res = 0;
                if (length1 > length2) {
                    res = 1;
                } else if (length1 < length2) {
                    res = -1;
                }
                return res;
            }
        });
        personList.forEach(person -> {
            System.out.println(person);
        });
    }
}
//输出如下
默认按年龄排序
aa: 6
a: 18
aaaa: 21
aaa: 32
自定义按名字的长度排序
a: 18
aa: 6
aaa: 32
aaaa: 21
```

按照年龄排序时，我们定义：进行compare时，年龄大的Person>年龄小的Person，通过Collections.sort()时，会按照我们定义的规则，对集合中的Person按照年龄进行从小到大的排序；

按照名字长度排序时，我们定义：进行compare时，名字长的Person>名字短的Person，通过Collections.sort()时，会按照我们定义的规则，对集合中的Person按照名字长度从小到大的排序；


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://maxwell.gitbook.io/way-to-architect/java-yu-yan/ji-he/ji-he-gai-shu/bi-jiao-qi-comparator.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
