关于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,但 ...
随机推荐
- Git在已有的分支上新建个人分支开发
在Dev分支上新建一个分支(可以通过Git TE网页创建) 然后就可以从Source下拉列表中看到新建的分支(new_name1)了. 远程分支创建完成之后,就可以在本机上面使用Git GUI Her ...
- 安装pytorch成功但cuda不可用
贴上我看的教程https://zhuanlan.zhihu.com/p/26871672 一开始想用pycharm装pytorch,但不知道为什么一直失败.后来只能conda pip安装 但conda ...
- Prometheus 监控Haproxy
Prometheus 监控Haproxy 普罗米修斯是一个完整的监控和趋势系统,包括基于时间序列数据的内置和主动刮削,存储,查询,绘图和警报,以下使用Prometheus+grafana对Haprox ...
- Qt文件系统之QFile
QFile文件操作 文件打开方式: QIODevice::NotOpen 0x0000 设备不打开.QIODevice::ReadOnly 0x0001 设备 以只读的方式打开.Q ...
- logging模块全总结
Python之日志处理(logging模块) 本节内容 日志相关概念 logging模块简介 使用logging提供的模块级别的函数记录日志 logging模块日志流处理流程 使用logging四 ...
- mysql表关联
mysql的表关联: left join(左联接) 返回包括左表中的所有记录和右表中联结字段相等的记录 right join(右联接) 返回包括右表中的所有记录和左表中联结字段相等的记录 inner ...
- Nginx 负载配置
简版的,详细参数需要自己微调. nginx.conf http{ upstream name { server 127.0.0.1:8777; server 127.0.0.1:8778; serve ...
- mysql 聚集函数 count 使用详解(转载)
本文将探讨以下问题 1.count(*) . count(n).count(null)与count(fieldName)2.distinct 与 count 连用3.group by (多个字段) 与 ...
- java基础回忆、复习(一)
一:浅拷贝与深拷贝: 对于基本数据类型,直接进行拷贝,String类型,有两种拷贝方式: 1:直接将原对象中的name的引用值拷贝给新对象的name字段.<浅拷贝> 2:根据原对象中的na ...
- 数组Array的API1
数组的方法arr.includes()arr.every(fn(val,i))arr.some(fn(val,i))arr.filter(fn(val,i))arr.map(fn(val,i))ar. ...