# 比较器comparator，compare函数升序、降序源码分析

## 0、前言

一直想不明白，compare函数如何通过返回值，就确定是升序还是降序呢，于是乎决定好好的先看看源码。

下面的代码实现了对自己写的Students类按照年龄升序的排序，就是通过对实现comparator接口，重写compare的方法，实现对排序的升序或者降序的控制：

import java.util.Arrays;
import java.util.Comparator;
public class learn_comparator{
public  static class Student {
public int id;
public String name;
public int age;
public Student(String name, int age, int id) {
this.id = id;
this.name = name;
this.age = age;
}
}
//重写compare方法，实现按照年龄的升序排列
public static class ageAscendingComparator implements Comparator<Student>{
@Override
public int compare(Student o1, Student o2) {
return o1.age-o2.age;

}
public static void printStudent(Student[] stu){
for (int i = 0; i <stu.length ; i++) {
System.out.print(stu[i].id);
System.out.print("  ");
System.out.print(stu[i].name);
System.out.print("  ");
System.out.println(stu[i].age);
}
}
public static void main(String[] args) {
Student s1=new Student("A",11,1);
Student s2=new Student("B",18,2);
Student s3=new Student("C",38,3);
Student s4=new Student("D",20,4);
Student s5=new Student("E",30,5);
Student s6=new Student("F",17,6);
Student[] arr_stu=new Student[]{s1,s2,s3,s4,s5,s6};
System.out.println("未排序前的输出如下：");
printStudent(arr_stu);
System.out.println("按照年龄升序排列后输出如下：");
Arrays.sort(arr_stu,new ageAscendingComparator());
printStudent(arr_stu);
}

}

1  A  11
2  B  18
3  C  38
4  D  20
5  E  30
6  F  17

1  A  11
6  F  17
2  B  18
4  D  20
5  E  30
3  C  38

## 1、关于comparator接口

Comparator是一个接口，它包含两种方法

int compare(T o1, T o2);
boolean equals(Object obj);

public boolean equals(Object obj) {
return (this == obj);
}

### 2、运行程序

Arrays.sort(arr_stu,new ageAscendingComparator());

public static <T> void sort(T[] a, Comparator<? super T> c) {
if (c == null) {
sort(a);
} else {

if (LegacyMergeSort.userRequested)
/*没看明白userRequested怎么得到的，没有走到这里 */
legacyMergeSort(a, c);
else//函数走到了这
TimSort.sort(a, 0, a.length, c, null, 0, 0);
}
}

TimSort.sort(a, 0, a.length, c, null, 0, 0);

static <T> void sort(T[] a, int lo, int hi, Comparator<? super T> c,
T[] work, int workBase, int workLen) {
//assert不满足，就报错
assert c != null && a != null && lo >= 0 && lo <= hi && hi <= a.length;

int nRemaining  = hi - lo;
if (nRemaining < 2)
return;  // Arrays of size 0 and 1 are always sorted
//MIN_MERGE为常数32,如果数组长度小于32，则会调用countRunAndMakeAscending()
//函数（重点，升序、降序的关键在此函数里），升序或者降序的数最后一个数的下标+1，
//赋值给initRunLen 数组分为一部分有序、一部分无序。
//然后使用二分查找插入排序，完后所有的排序
if (nRemaining < MIN_MERGE) {
int initRunLen = countRunAndMakeAscending(a, lo, hi, c);
binarySort(a, lo, hi, lo + initRunLen, c);
return;
}
***************************************************
********　　　>=32的部分，还未看　　**************
***************************************************

}

countRunAndMakeAscending(a, lo, hi, c);这是最重要的的部分了

private static <T> int countRunAndMakeAscending(T[] a, int lo, int hi,
Comparator<? super T> c) {
assert lo < hi;
//移动runHi来遍历
int runHi = lo + 1;
if (runHi == hi)
return 1;

// Find end of run, and reverse range if descending
if (c.compare(a[runHi++], a[lo]) < 0) { // Descending
//本例中，后面的只要比前面的小，就一直往后数
while (runHi < hi && c.compare(a[runHi], a[runHi - 1]) < 0)
runHi++;
//把降序反转
reverseRange(a, lo, runHi);
} else {                              // Ascending

//本例中，后面的只要比前面的大，就一直往后面数
while (runHi < hi && c.compare(a[runHi], a[runHi - 1]) >= 0)
runHi++;
}
//返回升序的边界
return runHi - lo;
}

binarySort(a, lo, hi, lo + initRunLen, c);

private static <T> void binarySort(T[] a, int lo, int hi, int start,
Comparator<? super T> c) {
//start=lo + initRunLen就是找到的升序的边界
assert lo <= start && start <= hi;
if (start == lo)
start++;
//遍历无序部分的每一个元素
for ( ; start < hi; start++) {
T pivot = a[start];

int left = lo;
int right = start;
assert left <= right;

while (left < right) {
//右移一位相当于除以二
int mid = (left + right) >>> 1;
if (c.compare(pivot, a[mid]) < 0)
//将范围向左，缩小一半
right = mid;
else
//向右缩小一半
left = mid + 1;
}
assert left == right;
int n = start - left;  // 需要移动的位数

switch (n) {
case 2:  a[left + 2] = a[left + 1];
case 1:  a[left + 1] = a[left];
break;
//要是移动的位数超过2，就用系统提供的方法；
default: System.arraycopy(a, left, a, left + 1, n);
}
a[left] = pivot;
}
}