关于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,但 ...
随机推荐
- bzoj5110: [CodePlus2017]Yazid 的新生舞会
Description Yazid有一个长度为n的序列A,下标从1至n.显然地,这个序列共有n(n+1)/2个子区间.对于任意一个子区间[l,r] ,如果该子区间内的众数在该子区间的出现次数严格大于( ...
- HTML如何实现斜体字
HTML实现斜体字的标签为<i>标签,用来实现字体倾斜,写法如下: 字体斜体:<i>内容</i> 案例:正常 斜体 当文字加入i标签以后字体就会成为斜体
- android 使用Canvas画箭头
public class MyCanvas extends View{ private Canvas myCanvas; private Paint myPaint=new Pai ...
- AD服务无法启动
转自网络资源:http://www.great-one.co.uk/archives/289 版本:win08 : 该方法支持hyper-v 虚拟机 启动报错: A Windows 2008 R2 D ...
- S2-052 RCE漏洞 初步分析
PS:初步分析,只是分析了Struts2 REST插件的部分,本来菜的抠脚不敢发,但看到各大中心发的也没比我高到哪里去,索性发出来做个记事! 漏洞描述 2017年9月5日,Apache Struts发 ...
- Java 环境配置 与 碰到的问题
小白记录,希望各位指点,长期整理修改 不定期更新,碰到的与之相关的会添加,做个小笔记,再次碰到可以更好的解决. JDK 下载:Oracle 配置方法:菜鸟教程 - Java 开发环境配置 作用 JAV ...
- tensorflow学习001——MNIST
1.MNIST是一个入门级的计算机视觉数据集,它包含各种手写数字图片 数据集被分成两部分:60000行的训练数据集(mnist.train)和10000行的测试数据集(mnist.test). 这样的 ...
- redis读书笔记
1.redis两种存储机制(持久化) Redis的存储机制分为:Snapshot和AOF 都先将内存存储在内存中. (1)Snapshot当数据累计到一定的阈值,就会触发dump将数据一次性写入到数据 ...
- 服务调用框架DataStrom
根据以前的命名服务,从新构建了下服务框架: 结构模式:c-center-s; 1.服务端: 服务端启动,讲自己的IP,端口注册到注册中心节点(master),然后注册自己的处理类(需要继承对应接口); ...
- .net core下载文件
上传的文件是在wwwroot下 通过保存的路径跟文件名称完成下载 public IActionResult DownloadFile() { var filePath = "/Upload ...