一、简要介绍
Arrays里我们用的比较多的就是sort函数,这里我写一点我的学习过程。
sort函数本身的排序性能是比较高的,它会在不同情况下运用不同的排序方法,如快排、二叉排,它给出了默认的从小到大的排序,同时也提供了自定义的排序方法,这里我会从基本数据类型的排序和自己创建对象进行排序来说明。(JDK版本为11)

二、基本数据类型的默认排序
1. int型

基本代码

class  sort1{
    public static void main(String[] args) {
        int[] help = new int[]{1,2,3,4,2,3,1,4,643,4};
        Arrays.sort(help);
    }}

这个的排序结果就是默认的从小到大排序,我们追sort的原码: 点击查看代码

public static void sort(int[] a) {
        DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0);
    }

发现它其实就是调用了一个sort(int[]a),其中调用了DualPivotQuicksort的sort方法,这个静态类的sort方法其实是很多种排序方法的一个综合,由于我是初学,这里不讲解

2. char型
我将上述代码里面的类型改为char,发现调用的还是同一个方法,这个方法的参数可以有很多种,基本上默认的数据类型都可以用,剩下的数据类型我就不一一举例。

点击查看代码

public static void sort(char[] a) {
        DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0);
    }

三、基本数据类型的自定义排序

Java里面的sort函数提供了一个Comparator接口使用户能够自定义排序顺序,如果需要自己定义排序顺序,需要实现一下Comparator接口,如图所示:

java Arrays 排序 java中arrays.sort排序原理_i++


可以看到sort这里可以接受两个参数,第一个是待排序的数组,第二个是一个Comparator接口。

我们拿字符数组排序来举例子:

点击查看代码

public static void main(String[] args) {
        Character[] help = new Character[]{'e','b','e','x','p','c','a'};
        //Arrays.sort(help);
        Arrays.sort(help,new Comparator<Character>(){
            @Override
            public int compare(Character o1, Character o2) {
                  return o1-o2;
            }
        });
    }

这是一个完整的自定义排序程序,我们使用内部类的形式实现了Comparator接口,可以看到再实现了Comparator接口中我们要实现它的compare的方法,这个方法就是我们自定义排序的关键,它有两个参数,两个char类型的封装类型的变量,而我们的返回值是一个int型,这是为什么?

下面我们来详细说明:

1、为什么compare的参数是两个封装类型?

我们这里追一下源码:
public static <T> void sort(T[] a, Comparator<? super T> c) 这是sort方法的真实样子,可以看见它利用范型,严格规定来传入参数的类型,这里我们可以大概看出为什么要传入对象类型,那这里我可以省略吗?当然可以!如果省略,这里默认你传入的是一个Object对象,代码如下:

点击查看代码

Arrays.sort(help,new Comparator(){
            @Override
            public int compare(Object o1, Object o2) {
                return (Character)o1-(Character) o2;
            }
        });

可以看到我这里没有指定范型,o1和o2两个对象就是Objiect类型,则在返回的时候需要进行强制类型转换。因此在我们排序不同类型的序列时,应该传入对应的封装类型或者对象类型。这是自定义排序的基本条件,同时定义数组的时候也需要讲定义类型改变为封装类型,如:

Character[] help = new Character[]{'e','b','e','x','p','c','a'};

2、为什么我们的返回值是两个对象相减,这里我们继续追原码:

这是sort函数的全貌,可以看到,当我们传入的数组不为0时,真正起排序作用的是TimSort.sort(),因为sort会根据传入待排序数组的类型,长度等进行合适的选择,还有更多的__Sort对象含有这个sort方法,而我们的例子这里调用的是TimSort里面的sort方法

点击查看代码

public static <T> void sort(T[] a, Comparator<? super T> c) {
        if (c == null) {
            sort(a);
        } else {
            if (LegacyMergeSort.userRequested)
                legacyMergeSort(a, c);
            else
                TimSort.sort(a, 0, a.length, c, null, 0, 0);
        }
    }

我们直接进入真正行使排序功能的代码:

点击查看代码

assert lo < hi;
        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;

本文不关心如何排序,我们着重看compare方法起了什么作用,注意看这两句代码:

if (c.compare(a[runHi++], a[lo]) < 0)
  while (runHi < hi && c.compare(a[runHi], a[runHi - 1]) >= 0)

可以看到这里直接调用了我们所实现的compare方法,用来进行排序里面的判断,这里真正的原理清楚了,原来我们返回的值可以直接影响到整个排序的进程,而返回值的正负是判断的关键,所以compare的返回值返回的是一个int型:

点击查看代码

public int compare(Character o1, Character o2) {
                  return o1-o2;
            }

这里虽然返回的是两个char的封装对象相减,但在计算的时候会自动解封装,转换为两个实数相减,最后返回一个int型的变量,解封装源码:

点击查看代码

public char charValue() {
        return value;
    }

返回的int值的正负影响到真正的排列顺序,而我们想要改变排列顺序就很简单,转换一下o1和o2的顺序即可,让返回正数的情况返回负数。基本上自定义排序的原理就在于此,那我们是否可以自己来实现这样的原理,当然可以!下面我用冒泡排序来演示一下。

四、自己实现自定义排序的原理(利用冒泡排序)

点击查看代码

public static void main(String[] args) {
       int []a = new int[]{1,2,3,2,3,4,52,3};
       for(int i = 0; i < a.length; i++){
           for(int j = 0; j < a.length-i-1;j++){
               if(compare(a[j],a[j+1]) > 0){
                   int tem = a[j];
                   a[j] = a[j+1];
                   a[j+1] = tem;
               }
           }
       }

       for(int i = 0;i < a.length; i++){
           System.out.print(a[i]+"\t");
       }
    }
    public static  int compare(int o1,int o2){
        return o1-o2;
    }

可以看到我们利用了我们自己实现的compare方法对冒泡排序中的判断条件进行了干预,造成了我们可以利用o1和o2的顺序来对最后的排序结果进行干预,核心就是下面的代码:

 if(compare(a[j],a[j+1]) > 0)
public static  int compare(int o1,int o2){         return o1-o2;     }