【Java】【常用类】 Arrays工具类 源码学习
虽然在数组的随笔中有说过,但实际上应该仔细深入一下源码进行分析
源码没有想象中的高大上,代码终究还是写给人看的,可读性大于执行性
最小阵列排序:1 乘 2的13次方 = 8192
学识浅薄,暂时还不明白这个常量在数组工具类的意义
通过翻译的介绍,说明这是并行排序最小长度的要求
【并行排序的最小数组长度】
- 算法不会进一步划分排序任务。使用
- 较小的大小通常会导致
- 使并行加速不太可能的任务。
private static final int MIN_ARRAY_SORT_GRAN = 1 << 13;
私有化的构造器,因为是工具类,设计者认为不应该产生实例
【抑制默认构造函数,确保不可实例化。】
// Suppresses default constructor, ensuring non-instantiability. private Arrays() {}
一个固定的静态内部类 叫自然顺序类
实现了可比较接口,和重写了比较方法,暂时还不知道其中的用意
static final class NaturalOrder implements Comparator<Object> { @SuppressWarnings("unchecked") public int compare(Object first, Object second) { return ((Comparable<Object>)first).compareTo(second); } static final NaturalOrder INSTANCE = new NaturalOrder(); }
长度范围检查
设计者认为所有工具方法,都应该先确认一下参数注入的数组的正确性
所以设计了长度检查,如果不符合描述,直接丢异常出去交给调用者处理检查
- 如果起始索引大于截至索引,抛出不合理的参数异常,并指明错误参数
- 如果起始位置小于0,也就是小于第一个元素的位置索引 ,抛出越界异常
- 如果截至位置大于数组的长度 抛出越界异常
/** * Checks that {@code fromIndex} and {@code toIndex} are in * the range and throws an exception if they aren't. */ private static void rangeCheck(int arrayLength, int fromIndex, int toIndex) { if (fromIndex > toIndex) { throw new IllegalArgumentException( "fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")"); } if (fromIndex < 0) { throw new ArrayIndexOutOfBoundsException(fromIndex); } if (toIndex > arrayLength) { throw new ArrayIndexOutOfBoundsException(toIndex); } }
可以看到这个排序调用的是一个名叫【双枢轴快速排序类的排序方法】
只看过快速排序,哪儿见过这算法,打个mark留意一下把,
因为只注入一个数组的参数,所以不需要上面范围检查
public static void sort(int[] a) { DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0); }
如果是针对数组的一个片段的排序,这个排序的重载就会调用范围检查
public static void sort(int[] a, int fromIndex, int toIndex) { rangeCheck(a.length, fromIndex, toIndex); DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0); }
基本类型的重载
除了对基本类型排序之外,还有对引用类型排序的支持!
但是具体实现的算法还是没看懂,只能标记一下了
public static void sort(Object[] a) { if (LegacyMergeSort.userRequested) legacyMergeSort(a); else ComparableTimSort.sort(a, 0, a.length, null, 0, 0); } /** To be removed in a future release. */ private static void legacyMergeSort(Object[] a) { Object[] aux = a.clone(); mergeSort(aux, a, 0, a.length, 0); }
并行排序、又称串行排序,用于多线程相关的排序
看不懂,我太菜了。。。。
备注说明了这个方法是从1.8开始有的
public static void parallelSort(byte[] a) { int n = a.length, p, g; if (n <= MIN_ARRAY_SORT_GRAN || (p = ForkJoinPool.getCommonPoolParallelism()) == 1) DualPivotQuicksort.sort(a, 0, n - 1); else new ArraysParallelSortHelpers.FJByte.Sorter (null, a, new byte[n], 0, n, 0, ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ? MIN_ARRAY_SORT_GRAN : g).invoke(); }
也是配备了基本类型和引用类型的重载
并行前缀方法
跟并行排序配套使用的方法... 依旧不懂
public static <T> void parallelPrefix(T[] array, BinaryOperator<T> op) { Objects.requireNonNull(op); if (array.length > 0) new ArrayPrefixHelpers.CumulateTask<> (null, op, array, 0, array.length).invoke(); }
对应的类型只有这么几个重载
官方的二分查找,在获取中轴游标时采用的位运算 无符号右移1,也就是除2
// Like public version, but without range checks. private static int binarySearch0(long[] a, int fromIndex, int toIndex, long key) { int low = fromIndex; int high = toIndex - 1; while (low <= high) { int mid = (low + high) >>> 1; long midVal = a[mid]; if (midVal < key) low = mid + 1; else if (midVal > key) high = mid - 1; else return mid; // key found } return -(low + 1); // key not found. }
对应的基本和引用类型的重载
比较两个数组之间是否相同 地址一样 或者 数组的长度和元素都是一样
public static boolean equals(int[] a, int[] a2) { if (a==a2) return true; if (a==null || a2==null) return false; int length = a.length; if (a2.length != length) return false; for (int i=0; i<length; i++) if (a[i] != a2[i]) return false; return true; }
引用类型数组增加了对元素对象的比较
public static boolean equals(Object[] a, Object[] a2) { if (a==a2) return true; if (a==null || a2==null) return false; int length = a.length; if (a2.length != length) return false; for (int i=0; i<length; i++) { Object o1 = a[i]; Object o2 = a2[i]; if (!(o1==null ? o2==null : o1.equals(o2))) return false; } return true; }
比较的重载
填充数组的重载 ,增加了范围检查设置,可以选数组的一个片段进行填充
public static void fill(long[] a, int fromIndex, int toIndex, long val) { rangeCheck(a.length, fromIndex, toIndex); for (int i = fromIndex; i < toIndex; i++) a[i] = val; }
复制数组直接调用的是系统类给的
然而系统类的复制方法是调用C++的方法
关于native描述的方法
https://www.cnblogs.com/b3051/p/7484501.html
public static char[] copyOf(char[] original, int newLength) { char[] copy = new char[newLength]; System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); return copy; }
片段复制
public static <T,U> T[] copyOfRange(U[] original, int from, int to, Class<? extends T[]> newType) { int newLength = to - from; if (newLength < 0) throw new IllegalArgumentException(from + " > " + to); @SuppressWarnings("unchecked") T[] copy = ((Object)newType == (Object)Object[].class) ? (T[]) new Object[newLength] : (T[]) Array.newInstance(newType.getComponentType(), newLength); System.arraycopy(original, from, copy, 0, Math.min(original.length - from, newLength)); return copy; }
转换成List集合,List是一个接口,实际上应该是由实现类完成的转换
@SafeVarargs @SuppressWarnings("varargs") public static <T> List<T> asList(T... a) { return new ArrayList<>(a); }
转换成字符串形式
- 空指针打印null
- 如果索引个数,也就是没有元素,返回空
- 使用Buider拼接字符串,遍历到最后返回
还有个深转换的,针对对象设计的方法...
public static String toString(long[] a) { if (a == null) return "null"; int iMax = a.length - 1; if (iMax == -1) return "[]"; StringBuilder b = new StringBuilder(); b.append('['); for (int i = 0; ; i++) { b.append(a[i]); if (i == iMax) return b.append(']').toString(); b.append(", "); } }
就先看到这儿了,剩下的几个方法都还没看懂是干嘛的