java.util.Arrays类源码分析

java.util.arrays 类源码阅读

 

sort1函数分析: (这里有7个版本的 ,分别对应的比较类型为:int,char,long,byte,short,double,float)

对于数组中的排序当长度小于7 时候将采用 插入排序

 

快速排序中

 

首先是 选择分治标准数

如果长度等于7 选取的为中间的那个数字作为分治的标准

如果长度大于7 小于等于40 将获取子数组中第一,中间和最后一位的数中获取中位数 作为分治的标准

如果长度大于40 将数组平分为8块获取其中的9个端点,分别取三位的中位数,同时获取最后三段的中位数作为分治的标准

 

将中间数找到之后,进行数组的两端数据进行下标遍历

如果是等于V的放到数组的两端

如果在下标小的大于V ,下标大的小于V的 则进行交换

如果遍历的下标两端已经逆向了 则退出

 

 

对于刚才比对之中的相等的值进行 水平替换到 数组的中间部分

 

根据判断 排序左右区间的 长度是否大于1 是递归调用 快速排序

 

vecswap 水平交换函数

将 a, b为起点的n长度的数据进行交换

 

med3 获取三个下标中数值的中位数

采用了?:的方法,进行了最小2次 最大3次比较的方法 来获取到 中位数

 

sort2 函数分析:(这里有5个版本的 ,分别对应的比较类型为:double,float)

排序采用了三个阶段:

第一:

移动任何的NAN和-0.0 到数组的尾部 ,其中使用到 Double.doubleToLongBits 用来判断 是否为-0.0

同时记录其中移动的个数

第二:

使用快速排序对合理的数据进行排序,排除上阶段移动的那些数据

 

第三:

将0.0替换成-0.0按照要求

 

 

mergeSort 归并排序函数

对于长度小于 7 的数组长度 采用插入排序

 

获取来源数组中的中间下标

从头和中间下标之间开始比较归并到 目标数组中

 

注意其中的下标计算:由于来源数组是进行数组复制产生的所以下标从 fromIndex-fromIndex 到 toIndex-fromIndex 之间

此外还包括了一个优化:

对于递归 归并排序是 如果发现 所要归并的两个子集合中第二个集合中的第一个 大于 第一个集合的最后一个 ,直接进行 目标数组数据的复制,不进行归并

 

cloneSubarray 克隆子数组的函数

通过反射获取到数组中的元素类型,通过Array的函数,动态的建立数组

再将来源的数组数据通过系统函数 System.arrayCopy到刚才实例化的数组中

 

rangeCheck 数组长度校验函数

通过比较相应的数组的起始和终止段的下标,以及相应的长度进行校验数组的合法性

包括了:

起始端不能小于0

终止段不能大于数组长度

起始端不能大于终止段

 

注:这里的终止段在其内部调用的时候,就是数组的长度,所以不要判断 等于数组长度的情况

 

binarySearch 二分查找函数(这里有8个版本的 ,分别对应的比较类型为:int,double,char,long,byte,float,short,object)

对于非浮点型的数据,都是采用类似的

和其中间的树进行比较,然后修改上界和下届的方法进行,确定值区间。如果最后没有找到就会返回 查询的这个值key所可以插入的位置

对于浮点数的类型这里相对于比较复杂:

需要对值的NAN -0.0 0.0 进行比较 定义的比较规则是 -0.0< 0.0 !NaN < NaN 的次序

 

equals 数组相等判断函数

按照如下的校验规则:

1. 地址相等 == true

2. 两者至少一个为空 false

3. 长度不相等        false

4. 以上条件都校验之后 遍历数组判断是否都相等

 

对于float 和 double的 两个的大小比较采用了 Double.doubleToLongBits转化为长整形方法进行判断

 

 

 

fill 填充函数 (这里有8个版本的 ,分别对应的类型为:int,double,char,long,byte,float,short,object)

1.先进行 rangeCheck 数组和填充范围校验

2.直接通过遍历数组 填充值

 

asList 将数据,数组转化成 list接口

通过实现一个 AbstractList 接口的内部类(归根到底不是外部的 java.util.ArrayList 类型),将数组数据注入到 list里面去

 

 

 

hashCode 函数

对于字节数为4的: 直接进行 x=31x+a 的运算,其中x初始为1 ,a 为需要计算哈希的数值 ,将所有的数组内的值进行这样的运算

对于字节数大于4的: 先对a进行 无符号移位之后与低32位进行异或 获取到32位的a 然后再进行字节数为4的运算(如上)

而对于浮点数 直接转化为标准的long 或者是 int的类型进行计算

 

对于布尔类型 则对 true->1231  false->1237

两个数 对应的 字节码为:

10011001111

10011010101

转化为int类型之后 再进行上面的 字节数为4的运算

 

toString函数

将数组数据 填充成 [data1,data2…] 的格式

 

deepHashCode函数

则是根据数组内部的元素为 数组的情况而设定的

对其内部的数组元素进行哈希计算后 通过上面的 x=31x+a 的公式进行计算

 

deepToString函数 深度打印类型,可针对多维度

如果为空 打印为null

 

估计需要输出的字符串的长度: 采用 length*20的方法

其中对于 长度小于0 的情况,设定输出的最大缓冲为 Integer.MAX_VALUE 就是最大值

 

对于数组中的简单元素直接使用其toString,

如果是数组类型则 判断是否为一元数组,

如果是 输出,

不是则通过和正在打印的集合进行判断,如果正在打印则输出[…], 如果没有递归调用打印数组的函数

 

在答应数组中维护一个正在打印的数据集,是为了避免在打印递归嵌套中,出现了 死循环的情况,可以很好的避免栈溢出的情况

 

 

 

deepEquals 函数

和deepHashCode函数类型,对于其中元素为数组的情况,进行深度的比对

规则为:

1.地址 ==

2.非空

3.长度

4.元素值

 

 

 

写在后面:

通过对Arrays代码学习,可以了解到一些基本的操作技巧:

1.对于 2的运算 采用移位 提高效率

2.在对浮点数 进行操作时候要时刻注意 NAN !NAN -0.0 0.0 直接的区别,在于其 二进制表示有很大的区别

3.在简单的快速排序,归并排序 时候 ,通过整合插入排序和简单优化 来提高速度

比如:

快速排序的 分治参考数的选取 对于不同的长度的数组 要采取不同的策略,而对于在比较数值时候,通过进行等值数的两次移动来增加排序的效率

而对于归并排序中 对于需要归并的两个序列,判断其中的第一个序列的最后一个数和 第二个序列中的第一个数的大小来决定 是否需要进行归并

 

这里抛砖引玉一下,了解一些底层的代码可以有助于编写高效的代码。 乃至做出国人自己的底层

 

 

    原文作者:java源码分析
    原文地址: http://www.cnblogs.com/fartpig/articles/2880123.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞