java中java.util.Arrays类的详解
一、概述
这个类是我们以后开发中使用比较方便、频繁的一个工具类!
- Arrays这个类包含用于操作数组的各种方法(例如排序和搜索)。 此类还包含一个静态工厂,允许将数组视为列表。
- 如果指定的数组引用为null,则此类中的方法都抛出NullPointerException
二、常用方法
1. static List aList(T… a):返回由指定数组支持的固定大小的列表。
下面是aList的实现方法
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
}
其实,也就是通过ArrayList的构造方法来创建List!
底层是通过传入数组类型的数组,来创建ArrayList
先通过Objects.requireNonNull(array);判断参数不是null,返回数组对象,赋值给ArrayList类的数组private final E[] a中
关于ArrayList类如下:
private static class ArrayList<E> extends AbstractList<E>
implements RandomAccess, java.io.Serializable
{
private static final long serialVersionUID = -2764017481108945198L;
private final E[] a;//底层存储用数组
ArrayList(E[] array) {
a = Objects.requireNonNull(array);//判断传入参数是否为null,返回赋值给a
}
@Override
public int size() {
return a.length;
}
@Override
public Object[] toArray() {
return Arrays.copyOf(a, a.length, Object[].class);
}
...
}
2. equals:比较两个数组是否相等
- equals(boolean[] a, boolean[] a2)
如果两个指定的布尔数组彼此 相等 ,则返回 true
子 - equals(boolean[] a, int aFromIndex, int aToIndex, boolean[] b, int bFromIndex, int bToIndex)(范围值包含FromIndex,不包含ToIndex)
如果两个指定的布尔数组在指定范围内彼此 相等 ,则返回true。 - equals(T[] a, T[] a2, Comparator<? super T> cmp):按照指定比较器来判断是否相等
- equals方法里参数类型还有其他
- 底层是先比较地址值是否相等,然后比较是否为空,再然后比较长度是否不同,最后调用mismatch来查找第一个不匹配的位置,mismatch没有不匹配就返回-1,所以ArraysSupport.mismatch(a, a2, length) < 0,有不匹配就会大于0,<0就不成立,就返回false。
- 有范围的比较,开始先调用rangCheck检查范围是否合法,防止给定范围越界,就会抛出异常ArrayIndexOutOfBoundsException或者IllegalArgumentException,然后根据长度差来比较两个长度是否相同,最后调用mismatch来匹配返回结果。
底层源码如下:
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;
return ArraysSupport.mismatch(a, a2, length) < 0;
}
public static boolean equals(int[] a, int aFromIndex, int aToIndex,
int[] b, int bFromIndex, int bToIndex) {
rangeCheck(a.length, aFromIndex, aToIndex);
rangeCheck(b.length, bFromIndex, bToIndex);
int aLength = aToIndex - aFromIndex;
int bLength = bToIndex - bFromIndex;
if (aLength != bLength)
return false;
return ArraysSupport.mismatch(a, aFromIndex,
b, bFromIndex,
aLength) < 0;
}
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);
}
}
3. copyOf:复制数组副本
- copyOf(boolean[] original, int newLength)
从0开始截取newLength长度复制到新数组中 - copyOfRange(boolean[] original, int from, int to)
将指定范围内容复制到新数组中 - 底层是先拿到数组的类型,然后调用copyOf重载的另一个方法,先判断类型去创建一个新数组copy,最后调用System.arraycopy方法来实现原数组跟新数组copy的复制。最后返回新数组copy
测试代码:
String[] arr3 = {"a","bb","ds"};
String[] arr4 = {"a","bc","dd"};
//copyOf,copyOfRange
String[] arr3Copy = Arrays.copyOf(arr3, 2);
String[] arr4Copy = Arrays.copyOfRange(arr4, 0, 2);//包含前者不包含后者
System.out.println(arr3Copy.length);//2
System.out.println(Arrays.toString(arr3Copy));//[a, bb]
System.out.println(arr4Copy.length);//2
System.out.println(Arrays.toString(arr4Copy));//[a, bc]
源码:
public static <T> T[] copyOf(T[] original, int newLength) {
return (T[]) copyOf(original, newLength, original.getClass());
}
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
@SuppressWarnings("unchecked")
T[] copy = ((Object)newType == (Object)Object[].class)
? (T[]) new Object[newLength]
: (T[]) Array.newInstance(newType.getComponentType(), newLength);
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
return copy;
}
4. sort:排序
parallelSort :功能类似sort,都是给数组升序排序!
排序算法是并行排序合并,它将数组分解为自身排序然后合并的子数组。 当子阵列长度达到最小粒度时,使用适当的Arrays.sort方法对子阵列进行排序。 如果指定数组的长度小于最小粒度,则使用适当的Arrays.sort方法对其进行排序。 该算法需要的工作空间不大于原始数组的大小。 ForkJoin common pool用于执行任何并行任务
- sort(int[]a)
对数组进行排序 - sort(byte[] a, int fromIndex, int toIndex)
按升序对数组的指定范围进行排序。 - sort(T[] a, Comparator<? super T> c)
根据指定比较器引发的顺序对指定的对象数组进行排序 - 底层是:此类通过以下方式实现双枢轴快速排序算法:
弗拉基米尔·雅罗斯拉夫斯基、乔恩·本特利和乔什·布洛赫算法
在许多导致其他问题的数据集上提供O(n log(n))性能
快速排序将降级为二次性能,通常是
比传统(单轴)快速排序实现更快。
测试代码:
int[] arr = {8,15,2,14,25,66,2,19};
int[] arr2 = {21,2,23,11,4,22,19};
//sort 升序排序
Arrays.sort(arr);
System.out.println(Arrays.toString(arr));//[2, 2, 2, 2, 2, 2, 3, 3]
Arrays.sort(arr2,0,4);//前四个数排序
System.out.println(Arrays.toString(arr2));//[2, 11, 21, 23, 4, 22, 19]
int[] arr5 = {1,25,12,16,8,22,15,33};
Arrays.parallelSort(arr5);
底层代码:
public static void sort(int[] a) {
DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0);
}
5. binarySearch:二分查找关键字
- int binarySearch(int[] a,int key)
对数组排序后,利用二分查找指定key值 - binarySearch(byte[] a, int fromIndex, int toIndex, byte key)
使用二进制搜索算法搜索指定值的指定字节数组的范围 - 底层通过数组长度加入参数中,调用binarySearch0来查找,binarySearch是标准的二分查找算法!
底层源码:
public static int binarySearch(int[] a, int key) {
return binarySearch0(a, 0, a.length, key);
}
private static int binarySearch0(int[] a, int fromIndex, int toIndex,
int key) {
int low = fromIndex;
int high = toIndex - 1;
while (low <= high) {
int mid = (low + high) >>> 1;
int 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.
}
6. fill:填充覆盖
- fill(boolean[] a, boolean val)
将指定的布尔值分配给指定的布尔数组的每个元素。 - fill(boolean[] a, int fromIndex, int toIndex, boolean val)
将指定的布尔值分配给指定的布尔数组的指定范围的每个元素。 - 参数类型还有其他
- 底层是 遍历数组每个元素,全部赋值为指定值
public static void fill(int[] a, int val) {
for (int i = 0, len = a.length; i < len; i++)
a[i] = val;
}
7.compare:比较大小
- compare(boolean[] a, boolean[] b)
字典顺序去比较两个参数 - compare(double[] a, int aFromIndex, int aToIndex, double[] b, int bFromIndex, int bToIndex)
指定范围做比较 - compare(T[] a, T[] b, Comparator<? super T> cmp)
按照指定比较器来比较两个数组大小
源码:
public static <T extends Comparable<? super T>> int compare(T[] a, T[] b) {
if (a == b)
return 0;
// A null array is less than a non-null array
if (a == null || b == null)
return a == null ? -1 : 1;
int length = Math.min(a.length, b.length);
for (int i = 0; i < length; i++) {
T oa = a[i];
T ob = b[i];
if (oa != ob) {
// A null element is less than a non-null element
if (oa == null || ob == null)
return oa == null ? -1 : 1;
int v = oa.compareTo(ob);
if (v != 0) {
return v;
}
}
}
return a.length - b.length;
}
8.mismatch:查找第一个不匹配位置
- mismatch(boolean[] a, boolean[] b)
查找并返回两个 boolean数组之间第一个不匹配的索引,否则如果未找到不匹配则返回-1。 - mismatch(boolean[] a, int aFromIndex, int aToIndex, boolean[] b, int bFromIndex, int bToIndex)
查找并返回指定范围内两个 boolean数组之间第一个不匹配的相对索引,否则返回-1(如果未找到不匹配)。 - 参数类型还有其他
9.toString
输出数组信息
底层遍历数组,用StringBuilder来拼接[ ] ,来返回拼接的String
public static String toString(int[] 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(", ");
}
}
10.stream :返回对应类型流
- stream(double[] array)
返回以指定数组作为源的顺序DoubleStream - stream(double[] array, int startInclusive, int endExclusive)
返回指定数组的指定范围作为其源的顺序DoubleStream 。 - 其他类型类推
总结
这些是我对常用的方法做了简单的收集整理,不得不说Arrays的底层实现真的很nb,值得反复看很多遍,这种编程思想值得学习借鉴!
未经允许不得转载!转载请注明来源。