/**
下面在自己代码中使用Collections.sort()方法去比较Student对象,通过在自己写的类里面通过匿名内部类实现Comparator接口,这个接口是让你自己实现比较器的规则
*/
//把待排序的集合list 和 实现后的比较器Comparator一起传入Collections的sort方法
Collections.sort(list, new Comparator<Student>() {这行断点调试
@Override
public int compare(Student o1, Student o2) { //比较器规则
return o1.getAge()-o2.getAge();//升序 如果正数就把o1往后排,如果负数就把o1往前排,
// return o2.getAge()-o1.getAge();//降序
}
});

这里通过实现比较器接口实现排序
(自己重写compare()方法来返回一个整数或者负数,给sort()方法,然后底层其实使用的是二分排序)

进入Collections.java的以下方法:
public static <T> void sort(List<T> list, Comparator<? super T> c) {
list.sort(c); //这里断点
}

继续调试,进入ArrayList.java的sort()方法:
@Override
/unchecked/
public void sort(Comparator<? super E> c) {
final int expectedModCount = modCount;
Arrays.sort((E[]) elementData, 0, size, c); //这行断点
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
modCount++;
}

进入Arrays.java的sort()方法:(中其实是把上面数组elementData,0,size,比较器传进来)
即传了集合本身,起始索引,结束索引,比较器
public static <T> void sort(T[] a, int fromIndex, int toIndex,
Comparator<? super T> c) {
if (c == null) { //没有比较器的时候
sort(a, fromIndex, toIndex);
} else {
rangeCheck(a.length, fromIndex, toIndex);
if (LegacyMergeSort.userRequested)
legacyMergeSort(a, fromIndex, toIndex, c);
else
TimSort.sort(a, fromIndex, toIndex, c, null, 0, 0); //通过前面判断跳到这里
//这里也是集合本身,起始索引,结束索引,比较器,还有另外三个参数不知道作用
}
}

然后进入了TimeSort.java的sort()方法:
//a是集合本身,lo是起始索引,hi是结束索引,c是比较器
static <T> void sort(T[] a, int lo, int hi, Comparator<? super T> c,
T[] work, int workBase, int workLen) {
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

// If array is small, do a "mini-TimSort" with no merges
if (nRemaining < MIN_MERGE) {
//a是集合本身,lo是起始索引,hi是结束索引,c是比较器
int initRunLen = countRunAndMakeAscending(a, lo, hi, c);
binarySort(a, lo, hi, lo + initRunLen, c);
return;
}

然后进入同一类(TimeSort.java)中的countRunAndMakeAscending()方法:
//a是集合本身,lo是起始索引,hi是结束索引,c是比较器
private static <T> int countRunAndMakeAscending(T[] a, int lo, int hi,
Comparator<? super T> c) {
assert lo < hi;
int runHi = lo + 1; //起始索引+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;
}

调用逻辑:
首先自己使用Collections.sort()比较对象的时候要实现比较器接口,然后把待排序的集合与比较器一起传入sort方法里
Collections.sort(list, new Comparator<Student>() {
@Override //下面重写接口抽象方法
});
public static <T> void sort(List<T> list, Comparator<? super T> c)
可以看到Collections.sort中的list传到了 List<T> list中的list,而匿名内部类对象传给 Comparator<? super T> c中的c.然后这个方法里使用了list.sort(c);然后会进入ArrayList的sort方法
运行到Arrays.sort((E[]) elementData, 0, size, c);这行后,调用Arrays的sort方法,再通过一些判断跳转到 TimSort.sort(a, fromIndex, toIndex, c, null, 0, 0); //通过前面判断跳到这里,进入TimSort.sor()方法,通过判断进入了ountRunAndMakeAscending(a, lo, hi, c); 这个是TimeSort类的方法:然后通过以下代码比较:
if (c.compare(a[runHi++], a[lo]) < 0) { // Descending
//这里compare方法先拿a[1]和a[0]比较
while (runHi < hi && c.compare(a[runHi], a[runHi - 1]) < 0)
//如果符合c.compare(a[1],a[0])<0,就循环判断c.compare(a[2],a[1]) c.compare(a[3],a[2])
runHi++;
//如果a[i]<a[i-1]执行交换,把较大的数换到后面
reverseRange(a, lo, runHi);
} else { // Ascending
while (runHi < hi && c.compare(a[runHi], a[runHi - 1]) >= 0)
//如果a[i]>a[i-1]不用交换
runHi++;
}

return runHi - lo;
}

关于Collections.sort()排序方法的源码探索的更多相关文章

  1. Scala 深入浅出实战经典 第41讲:List继承体系实现内幕和方法操作源码揭秘

    Scala 深入浅出实战经典 第41讲:List继承体系实现内幕和方法操作源码揭秘 package com.parllay.scala.dataset /** * Created by richard ...

  2. 三种排序算法python源码——冒泡排序、插入排序、选择排序

    最近在学习python,用python实现几个简单的排序算法,一方面巩固一下数据结构的知识,另一方面加深一下python的简单语法. 冒泡排序算法的思路是对任意两个相邻的数据进行比较,每次将最小和最大 ...

  3. [Java源码解析] -- String类的compareTo(String otherString)方法的源码解析

    String类下的compareTo(String otherString)方法的源码解析 一. 前言 近日研究了一下String类的一些方法, 通过查看源码, 对一些常用的方法也有了更透彻的认识,  ...

  4. Pycharm中查看方法的源码

    方法1.鼠标放在函数上,Ctrl+B,看源码 方法2.将光标移动至要查看的方法处,按住ctrl 键,点击鼠标左键,即可查看该方法的源码.

  5. 如何查看laravel门脸类包含方法的源码

    以Route门脸类为例,我们定义路由时使用的就是Route门脸类,例如我们在web.php中定义的路由 use Illuminate\Support\Facades\Route; Route::get ...

  6. 《JAVA高并发编程详解》-Thread start方法的源码

    Thread start方法的源码:

  7. HttpServlet中service方法的源码解读

    前言     最近在看<Head First Servlet & JSP>这本书, 对servlet有了更加深入的理解.今天就来写一篇博客,谈一谈Servlet中一个重要的方法-- ...

  8. Tars | 第4篇 Subset路由规则业务分析与源码探索

    目录 前言 1. Subset不是负载均衡 1.1 任务需求 1.2 负载均衡源码结构图 1.3 负载均衡四种调用器 1.4 新增两种负载均衡调用器 1.5 Subset应该是"过滤&quo ...

  9. Eureka源码探索(一)-客户端服务端的启动和负载均衡

    1. Eureka源码探索(一)-客户端服务端的启动和负载均衡 1.1. 服务端 1.1.1. 找起始点 目前唯一知道的,就是启动Eureka服务需要添加注解@EnableEurekaServer,但 ...

随机推荐

  1. LeetCode——688. Knight Probability in Chessboard

    一.题目链接:https://leetcode.com/problems/knight-probability-in-chessboard/ 二.题目大意: 给定一个N*N的棋盘和一个初始坐标值(r, ...

  2. 20175311 2018-2019-2 《Java程序设计》第7周学习总结

    20175311 2018-2019-2 <Java程序设计>第7周学习总结 教材学习内容总结 这一周我主要学习了第八章的内容-常用实用类String类 构造String对象 字符串的并置 ...

  3. wireshark过滤器

    一 概况 本文是对wireshark抓包过滤器, 跟显示过滤器的总结 由于一些未知的原因, 这俩过滤器的语法并不一样! 我大概知道为什么不一样了, 因为这俩出现的顺序不一样, 抓包过滤器先出现的, 可 ...

  4. [STM32F103]串口UART配置

    l 串口时钟使能,GPIO时钟使能: RCC_APB2PeriphClockCmd(); l 串口复位: USART_DeInit(); 这一步不是必须的 l GPIO端口模式设置: GPIO_Ini ...

  5. ubuntu go环境安装搭建

    一.安装必备环境 sudo apt-get install git golang-go vim sublime-text-installer 如果出现安装错误,进行修复安装: sudo apt-get ...

  6. UI自动化之元素定位(xpath、css)

    很早之前就已经写过自动化了,不过点着功能久了就会容易忘记元素定位,尤其是xpath和css定位,所以就花点时间做下总结收集. xpath有两种定位: 一.绝对路径(不推荐使用,除非已经使用了所有方式仍 ...

  7. IIS 字符串过长

    jquery.datatable.js---弹窗要用极速模式 <?xml version="1.0" encoding="utf-8"?><c ...

  8. MVC的开发模式简单介绍

    MVCM model 模型 实体类和业务和dao dao(数据库访问对象)V view 视图 jspC controller 控制器 servlet 作用:视图和逻辑分离 开发设计顺序 1.设计数据库 ...

  9. springboot线程池任务调度类 -- ThreadPoolTaskScheduler介绍

    springboot中有一个bean,ThreadPoolTaskScheduler,可以很方便的对重复执行的任务进行调度管理:相比于通过java自带的周期性任务线程池ScheduleThreadPo ...

  10. C# 拖拽事件

    实现一个textBox像另一个TextBox拖拽数据. 一个控件想要被拖入数据的前提是AllowDrop属性为true. 所以,首先需要将被拖入数据的textBox的AllowDrop属性设置为Tru ...