1、简介
Arrays类包含在java.util包中,是一个处理数组的工具类。Arrays类中包含了多种处理数组的方法,比如排序和查找。同时,Arrays类还有一个静态工厂可以将数组转化为List。
在Arrays类中,如果特定的数组引用为空,所有的方法都会抛出NullPointerExpection异常,除非做出说明。
Java中的好多类都用到了Arrays类来处理数组,比如String类中处理字符数组value。
Java中的Arrays类中几乎所有有用的方法都是静态的,而且类的构造函数被定义为私有的:
// Suppresses default constructor, ensuring non-instantiability.
private Arrays() {}
这是为了不实例化Arrays类,把它当做一个工具调用即可。
2、主要方法
(1)sort()
对于Arrays类来说,排序是一个非常重要的方法。Arrays类中对所有的基本类型都重载了sort函数,也对Object进行了重载,使得sort可以满足各种排序的需要。
Arrays中的sort方法使用的是双轴快速排序算法,即Dual-Pivot Quicksort。一般的快速排序使用一个轴将一个数组分为两部分分别排序然后合并,而Dual-Pivot Quicksort算法使用两个轴将数组分为三部分分别排序然后合并。这里对算法不做过多的介绍,只是简单的介绍函数的使用。
sort方法代码如下:
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);
}
对所有的类型的sort方法中都是这两种形式,其中第二种对下标范围进行检查,代码如下:
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);
}
}
sort方法都是进行升序排序。具体的API如下:
- void sort(int[] a)
- void sort(int[] a,int fromIndex,int toIndex)
- void sort(long[] a)
- void sort(long[] a,int fromIndex,int toIndex)
- void sort(short[] a)
- void sort(short[] a,int fromIndex,int toIndex)
- void sort(char[] a)
- void sort(char[] a,int fromIndex,int toIndex)
- void sort(float[] a)
- void sort(float[] a,int fromIndex,int toIndex)
- void sort(double[] a)
- void sort(double[] a,int fromIndex,int toIndex)
- void sort(byte[] a)
- void sort(byte[] a,int fromIndex,int toIndex)
Arrays类中对Object类进行重载的sort方法可以使用归并排序。方法定义如下:
public static void sort(Object[] a) {
if (LegacyMergeSort.userRequested)
legacyMergeSort(a);
else
ComparableTimSort.sort(a, 0, a.length, null, 0, 0);
}
然后调用内部方法:
private static void legacyMergeSort(Object[] a,
int fromIndex, int toIndex) {
Object[] aux = copyOfRange(a, fromIndex, toIndex);
mergeSort(aux, a, fromIndex, toIndex, -fromIndex);
}
之后使用结合了插入排序的归并排序。APIs:
- void sort(Object[] a)
- void sort(Object[] a,int fromIndex,int toIndex)
(2)paralleleSort()(1.8开始)
从1.8开始,Arrays加入了parallelSort方法,parallelSort方法首先将数组分成已经排好序的各个部分,然后再归并。具体方法如下:
- void parallelSort(int[] a)
- void parallelSort(int[] a,int fromIndex,int toIndex)
- void parallelSort(long[] a)
- void parallelSort(long[] a,int fromIndex,int toIndex)
- void parallelSort(short[] a)
- void parallelSort(short[] a,int fromIndex,int toIndex)
- void parallelSort(char[] a)
- void parallelSort(char[] a,int fromIndex,int toIndex)
- void parallelSort(float[] a)
- void parallelSort(float[] a,int fromIndex,int toIndex)
- void parallelSort(double[] a)
- void parallelSort(double[] a,int fromIndex,int toIndex)
- void parallelSort(byte[] a)
- void parallelSort(byte[] a,int fromIndex,int toIndex)
- <T extends Comparable<? super T>> void parallelSort(T[] a)
- <T extends Comparable<? super T>> void parallelSort(T[] a, int fromIndex, int toIndex)
<T> void parallelSort(T[] a, Comparator<? super T> cmp)
- <T> void parallelSort(T[] a, int fromIndex, int toIndex,Comparator<? super T> cmp)
(3)parallelPrefix()(1.8开始)
从1.8开始Java加入了这个方法,对数组中的每个元素,使用给定的方法,来计算前缀累计。比如,数组是[2,1,4,0,3],方法是加,那么结果就是[2,3,7,7,10]。具体方法如下:
- <T> void parallelPrefix(T[] array, BinaryOperator<T> op)
- <T> void parallelPrefix(T[] array, int fromIndex,int toIndex, BinaryOperator<T> op)
- void parallelPrefix(long[] array, LongBinaryOperator op)
- void parallelPrefix(long[] array, int fromIndex, int toIndex, LongBinaryOperator op)
- void parallelPrefix(double[] array, DoubleBinaryOperator op)
- void parallelPrefix(double[] array, int fromIndex, int toIndex, DoubleBinaryOperator op)
- void parallelPrefix(int[] array, IntBinaryOperator op)
- void parallelPrefix(int[] array, int fromIndex, int toIndex, IntBinaryOperator op)
(4)binarySearch()
二分查找也是数组操作中的重要部分,binarySearch方法返回数组中指定元素第一次出现的位置(数组必须排好序的,否则没有意义),如果数组中没有这个元素,就返回这个元素应该插入位置的下标加上1的反。比如:
int[] nums={1,2,3,4,5,7,8,9};
System.out.println(Arrays.binarySearch(nums, 6));
结果为6。
binarySearch方法对所有的基本类型进行了重载:
- int binarySearch(long[] a, long key)
- int binarySearch(long[] a, int fromIndex, int toIndex, long key)
- int binarySearch(int[] a, int key)
- int binarySearch(int[] a, int fromIndex, int toIndex, int key)
- int binarySearch(short[] a, short key)
- int binarySearch(short[] a, int fromIndex, int toIndex, short key)
- int binarySearch(char[] a, char key)
- int binarySearch(char[] a, int fromIndex, int toIndex, char key)
- int binarySearch(byte[] a, byte key)
- int binarySearch(byte[] a, int fromIndex, int toIndex, byte key)
- int binarySearch(double[] a, double key)
- int binarySearch(double[] a, int fromIndex, int toIndex,double key)
- int binarySearch(float[] a, float key)
- int binarySearch(float[] a, int fromIndex, int toIndex, float key)
- int binarySearch(Object[] a, Object key)
- int binarySearch(Object[] a, int fromIndex, int toIndex,Object key)
- <T> int binarySearch(T[] a, T key, Comparator<? super T> c)
- <T> int binarySearch(T[] a, int fromIndex, int toIndex,T key, Comparator<? super T> c)
(5)equals()
equals方法比较两个数组是否相同,主要代码如下:
public static boolean equals(long[] a, long[] 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;
}
首先比较是否是同一个引用,如果是那肯定相同。如果不是然后比较元素内容,只有当长度相同并且内容也相同时返回true。对于元素也是数组的数组来说,需要使用deepEquals方法。equals方法也对所有的类型进行了重载:
- boolean equals(long[] a, long[] a2)
- boolean equals(int[] a, int[] a2)
- boolean equals(short[] a, short a2[])
- boolean equals(char[] a, char[] a2)
- boolean equals(byte[] a, byte[] a2)
- boolean equals(boolean[] a, boolean[] a2)
- boolean equals(double[] a, double[] a2)
- boolean equals(float[] a, float[] a2)
- boolean equals(Object[] a, Object[] a2)
- boolean deepEquals(Object[] a1, Object[] a2)
(6)fill()
fill方法在数组中将指定位置的元素替换为指定的元素:
- void fill(long[] a, long val)
- void fill(long[] a, int fromIndex, int toIndex, long val)
- void fill(int[] a, int val)
- void fill(int[] a, int fromIndex, int toIndex, int val)
- void fill(short[] a, short val)
- void fill(short[] a, int fromIndex, int toIndex, short val)
- void fill(char[] a, char val)
- void fill(char[] a, int fromIndex, int toIndex, char val)
- void fill(byte[] a, byte val)
- void fill(byte[] a, int fromIndex, int toIndex, byte val)
- void fill(boolean[] a, boolean val)
- void fill(boolean[] a, int fromIndex, int toIndex,boolean val)
- void fill(double[] a, double val)
- void fill(double[] a, int fromIndex, int toIndex,double val)
- void fill(float[] a, float val)
- void fill(float[] a, int fromIndex, int toIndex, float val)
- void fill(Object[] a, Object val)
- void fill(Object[] a, int fromIndex, int toIndex, Object val)
(7)数组的复制(copyOf和copyOfRange)
Arrays类中提供了一些可以复制数组内容的方法copyOf和copyOfRange,前者需要两个参数original和newLength,original是需要复制的数组,newLength是新数组的大小。如果newLength小于等于original的大小,那么新数组的内容和original中相应部分的内容一样;如果newLength大于original的大小,那么就用null来补充。copyOfRange是范围复制,还需要两个参数from和to,这两个参数指定了original中需要复制的内容的范围,同样,如果to大于original的大小,不足的部分用null补充。比如:
int[] nums={1,2,3,4,5,7,8,9};
int[] newNums=Arrays.copyOf(nums, nums.length+2);
结果为:
[1, 2, 3, 4, 5, 7, 8, 9, 0, 0]
所有的方法如下:
- <T> T[] copyOf(T[] original, int newLength)
- <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType)
- byte[] copyOf(byte[] original, int newLength)
- short[] copyOf(short[] original, int newLength)
- int[] copyOf(int[] original, int newLength)
- long[] copyOf(long[] original, int newLength)
- char[] copyOf(char[] original, int newLength)
- float[] copyOf(float[] original, int newLength)
- double[] copyOf(double[] original, int newLength)
- boolean[] copyOf(boolean[] original, int newLength)
- <T> T[] copyOfRange(T[] original, int from, int to)
- <T,U> T[] copyOfRange(U[] original, int from, int to, Class<? extends T[]> newType)
- byte[] copyOfRange(byte[] original, int from, int to)
- short[] copyOfRange(short[] original, int from, int to)
- int[] copyOfRange(int[] original, int from, int to)
- long[] copyOfRange(long[] original, int from, int to)
- char[] copyOfRange(char[] original, int from, int to)
- float[] copyOfRange(float[] original, int from, int to)
- double[] copyOfRange(double[] original, int from, int to)
- boolean[] copyOfRange(boolean[] original, int from, int to)
(8)hashCode()
hashCode方法根据数组的内容返回数组的哈希值,需要注意的是,如果数组里的元素也是数组,需要使用deepHashCode方法。deepHashCode方法采用递归的方式计算元素内容的哈希值。所有方法如下:
- int hashCode(long a[])
- int hashCode(int a[])
- int hashCode(short a[])
- int hashCode(char a[])
- int hashCode(byte a[])
- int hashCode(boolean a[])
- int hashCode(float a[])
- int hashCode(double a[])
- int hashCode(Object a[])
- int deepHashCode(Object a[])
(9)toString()
toString方法的内部使用StringBuilder来构造String。同样要注意的是数组的数组,需要调用deepToString方法。所有方法如下:
- String toString(long[] a)
- String toString(int[] a)
- String toString(short[] a)
- String toString(char[] a)
- String toString(byte[] a)
- String toString(boolean[] a)
- String toString(float[] a)
- String toString(double[] a)
- String toString(Object[] a)
- String deepToString(Object[] a)
(10)setAll()和parallelSetAll()
这两个方法是1.8新加入的,功能比较强大,可以使用一个自定义的生成器设置数组的内容,比如,给定一个数组,使每个元素变为它的平方,如果没有setAll和parallelSetAll的话,需要一个循环,但现在可以这样:
final int[] nums={1,2,3,4,5,7,8,9};
System.out.println("Before:");
for (int i : nums) {
System.out.print(i+" ");
}
Arrays.setAll(nums, new IntUnaryOperator(){
public int applyAsInt(int index)
{
return nums[index]*nums[index];
}
});
System.out.println("\nAfter setAll():");
for (int i : nums) {
System.out.print(i+" ");
}
Arrays.parallelSetAll(nums, new IntUnaryOperator(){
public int applyAsInt(int index)
{
return nums[index]*nums[index];
}
});
System.out.println("\nAfter parallelSetAll():");
for (int i : nums) {
System.out.print(i+" ");
}
结果:
Before:
1 2 3 4 5 7 8 9
After setAll():
1 4 9 16 25 49 64 81
After parallelSetAll():
1 16 81 256 625 2401 4096 6561
所有方法如下:
- <T> void setAll(T[] array, IntFunction<? extends T> generator)
- <T> void parallelSetAll(T[] array, IntFunction<? extends T> generator)
- void setAll(int[] array, IntUnaryOperator generator)
- void parallelSetAll(int[] array, IntUnaryOperator generator)
- void setAll(long[] array, IntToLongFunction generator)
- void parallelSetAll(long[] array, IntToLongFunction generator)
- void setAll(double[] array, IntToDoubleFunction generator)
- void parallelSetAll(double[] array, IntToDoubleFunction generator)
(11)转为List
Arrays类中的asList方法可以将一个数组转换为List,Arrays类中定义了一个内部类ArrayList,用来做这个转换。定义如下:
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
}
比如:
<span style="white-space:pre"> </span>Integer[] nums={1,2,3,4,5,7,8,9};
List<Integer> lists=Arrays.asList(nums);
System.out.println(lists);
结果:
[1, 2, 3, 4, 5, 7, 8, 9]
注意,nums不能是int[],如果是这样的话,编译器就把nums当做一个Object了,认为需要把nums转换为只含有nums这一个元素的List<int[]>,所以会报List<int> 不能转换为List<int[]> 的错误。