关于Collections.sort()排序方法的源码探索
/**
下面在自己代码中使用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()排序方法的源码探索的更多相关文章
- Scala 深入浅出实战经典 第41讲:List继承体系实现内幕和方法操作源码揭秘
Scala 深入浅出实战经典 第41讲:List继承体系实现内幕和方法操作源码揭秘 package com.parllay.scala.dataset /** * Created by richard ...
- 三种排序算法python源码——冒泡排序、插入排序、选择排序
最近在学习python,用python实现几个简单的排序算法,一方面巩固一下数据结构的知识,另一方面加深一下python的简单语法. 冒泡排序算法的思路是对任意两个相邻的数据进行比较,每次将最小和最大 ...
- [Java源码解析] -- String类的compareTo(String otherString)方法的源码解析
String类下的compareTo(String otherString)方法的源码解析 一. 前言 近日研究了一下String类的一些方法, 通过查看源码, 对一些常用的方法也有了更透彻的认识, ...
- Pycharm中查看方法的源码
方法1.鼠标放在函数上,Ctrl+B,看源码 方法2.将光标移动至要查看的方法处,按住ctrl 键,点击鼠标左键,即可查看该方法的源码.
- 如何查看laravel门脸类包含方法的源码
以Route门脸类为例,我们定义路由时使用的就是Route门脸类,例如我们在web.php中定义的路由 use Illuminate\Support\Facades\Route; Route::get ...
- 《JAVA高并发编程详解》-Thread start方法的源码
Thread start方法的源码:
- HttpServlet中service方法的源码解读
前言 最近在看<Head First Servlet & JSP>这本书, 对servlet有了更加深入的理解.今天就来写一篇博客,谈一谈Servlet中一个重要的方法-- ...
- Tars | 第4篇 Subset路由规则业务分析与源码探索
目录 前言 1. Subset不是负载均衡 1.1 任务需求 1.2 负载均衡源码结构图 1.3 负载均衡四种调用器 1.4 新增两种负载均衡调用器 1.5 Subset应该是"过滤&quo ...
- Eureka源码探索(一)-客户端服务端的启动和负载均衡
1. Eureka源码探索(一)-客户端服务端的启动和负载均衡 1.1. 服务端 1.1.1. 找起始点 目前唯一知道的,就是启动Eureka服务需要添加注解@EnableEurekaServer,但 ...
随机推荐
- 使用命令行执行jmeter的方法
1. 简介 使用非 GUI 模式,即命令行模式运行 JMeter 测试脚本能够大大缩减所需要的系统资 本文介绍windows下以命令行模式运行的方法. 1.1. 命令介绍 jmeter -n -t & ...
- Scrapy实战篇(六)之爬取360图片数据和图片
本篇文章我们以360图片为例,介绍scrapy框架的使用以及图片数据的下载. 目标网站:http://images.so.com/z?ch=photography 思路:分析目标网站为ajax加载方式 ...
- three.js使用base64 图片创建Texture纹理
下面使用的是literallycanvas绘图,然后获取绘图结果为base64内容 var lc = LC.init( document.getElementById('canvas-output') ...
- python3 模拟鼠标和键盘操作
1. 安装pyperclip pip install pyperclip 使用方法复制 pyperclip.copy("hello world") 粘贴 pyperclip.pas ...
- Redux 学习总结
1.Redux 设计理念 Web 应用是一个状态机,视图与状态是一一对应的 所有的状态,保存在一个对象里面 2.基本概念和API Redux 的核心就是 store, action, reducer ...
- 权限模型AGDLP
关于权限模型,认真学习下AD+FS应用在企业中,使用AGDLP模型,即可. AD是微软最牛逼的设计之一.
- shell中使用类似Python的参数处理
params=$* for param in ${params} do name=$() value=$() if [[ "$name" = "run_type" ...
- uniapp仿h5+fire自定义事件触发监听
仿h5+fire自定义事件触发监听 uni-app调用 event.js 源码记录(点击查看) 1.js下载地址 [event.js](https://ext.dcloud.net.cn/plugin ...
- k8s 命令补全
安装:apt-get install bash-completion source <(kubectl completion bash) echo "source <(kubec ...
- this 的指向
使用 JavaScript 开发的时候,很多开发者多多少少会被 this 的指向搞蒙圈,但是实际上,关于 this 的指向,记住最核心的一句话:哪个对象调用函数,函数里面的this指向哪个对象. 下面 ...