java.util.Arrays 是数组工具,虽然源码有5000多行,但是考虑了多种数据类型,实现方法大致相同,理解起来很容易,主要有以下几类方法:
sort:为各种类型的数组排序binarySearch:二分查找equals:判断相等fill:将一个值填充到数组各项copyOf:从头拷贝数组内容copyOfRange:按范围拷贝数组内容hashCode:计算数组的哈希值toString:数组转字符串asList:数组转ListparallelSort:并行排序(1.8版本)parallelPrefix:并行前缀(1.8版本)spliterator:转成分离器(1.8版本)stream:转成流形式(1.8版本)
1 sort
下面是对int[]类型进行排序的方法,此外以下类型都使用了类似的方法:long[]、short[]、char[]、byte[]、float[]和double[]。
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);
} 可以看到Arrays.sort方法在进行数组范围检查后,直接调用了DualPivotQuicksort.sort方法,其中Arrays.rangeCheck方法的实现如下:
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);
}
} 2 binarySearch
下面是对int[]类型进行二分查找的方法,此外以下类型都使用了类似的方法:long[]、short[]、char[]、byte[]、float[]、double[]和Object[]。
public static int binarySearch(int[] a, int key) {
return binarySearch0(a, 0, a.length, key);
}
public static int binarySearch(int[] a, int fromIndex, int toIndex, int key) {
rangeCheck(a.length, fromIndex, toIndex);
return binarySearch0(a, fromIndex, toIndex, 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.
} 其中关于float和double类型的比较笔者将在equals方法中一同说明,下面再看一下对Object[]进行二分查找的实现:
private static int binarySearch0(Object[] a, int fromIndex, int toIndex, Object key) {
int low = fromIndex;
int high = toIndex - 1;
while (low <= high) {
int mid = (low + high) >>> 1;
@SuppressWarnings("rawtypes")
Comparable midVal = (Comparable)a[mid];
@SuppressWarnings("unchecked")
int cmp = midVal.compareTo(key);
if (cmp < 0)
low = mid + 1;
else if (cmp > 0)
high = mid - 1;
else
return mid; // key found
}
return -(low + 1); // key not found.
} 可以看到将Object对象强制转换为Comparable对象,这种方法日后可以借鉴。
3 equals
下面是对int[]类型进行相等比较的方法,此外以下类型都使用了类似的方法:long[]、short[]、char[]、byte[]、float[]、double[]、boolean[]和Object[]。
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;
} 可以看到比较的逻辑十分清晰:
- 内存地址相等,返回
true - 任意一者为
null,返回false - 如果数组长度不相等,返回
false - 依次比较数组的元素,有不相等的情况直接返回
false - 最后返回
true
各种数据类型的区别就在于依次比较数组元素的地方,其中long[]、short[]、char[]、byte[]、boolean[],都与int[]的实现一样。
下面看一下float[]和double[]和Object[]的相应实现:
for (int i=0; i<length; i++)
if (Float.floatToIntBits(a[i])!=Float.floatToIntBits(a2[i]))
return false; for (int i=0; i<length; i++)
if (Double.doubleToLongBits(a[i])!=Double.doubleToLongBits(a2[i]))
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;
} 这三种方法日后可以借鉴。
4 fill
下面是对int[]类型进行数组填充的方法,此外以下类型都使用了相同的方法:long[]、short[]、char[]、byte[]、float[]、double[]、boolean[]和Object[]。
public static void fill(int[] a, int val) {
for (int i = 0, len = a.length; i < len; i++)
a[i] = val;
}
public static void fill(int[] a, int fromIndex, int toIndex, int val) {
rangeCheck(a.length, fromIndex, toIndex);
for (int i = fromIndex; i < toIndex; i++)
a[i] = val;
} 5 copyOf
下面是对int[]类型进行从头拷贝数组的方法,此外以下类型都使用了相同的方法:long[]、short[]、char[]、byte[]、float[]、double[]和boolean[]。
public static int[] copyOf(int[] original, int newLength) {
int[] copy = new int[newLength];
System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength));
return copy;
} 创建一个长度为newLength的新数组,再调用本地方法System.arraycopy将两个数组的内容进行拷贝,拷贝的长度为原数组长度和新数组长度的较小值。
下面是Object[]的相应实现,主要的区别在创建新数组的过程:
@SuppressWarnings("unchecked")
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;
} 6 rangeCopy
下面是对int[]类型进行按范围拷贝数组的方法,此外以下类型都使用了相同的方法:long[]、short[]、char[]、byte[]、float[]、double[]和boolean[]。
public static int[] copyOfRange(int[] original, int from, int to) {
int newLength = to - from;
if (newLength < 0)
throw new IllegalArgumentException(from + " > " + to);
int[] copy = new int[newLength];
System.arraycopy(original, from, copy, 0, Math.min(original.length - from, newLength));
return copy;
} 下面是Object[]的相应实现,主要的区别在创建新数组的过程:
@SuppressWarnings("unchecked")
public static <T> T[] copyOfRange(T[] original, int from, int to) {
return copyOfRange(original, from, to, (Class<? extends T[]>) original.getClass());
}
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;
} 7 hashCode
下面是对int[]类型进行计算哈希值的方法,此外以下类型都使用了相同的方法:short[]、char[]、byte[]。
public static int hashCode(int a[]) {
if (a == null)
return 0;
int result = 1;
for (int element : a)
result = 31 * result + element;
return result;
} 其中boolean[]的实现有如下区别:
for (boolean element : a)
result = 31 * result + (element ? 1231 : 1237); 其中long[]的实现有如下区别:
for (long element : a) {
int elementHash = (int)(element ^ (element >>> 32));
result = 31 * result + elementHash;
} 其中float[]的实现有如下区别:
for (float element : a)
result = 31 * result + Float.floatToIntBits(element); 其中double[]的实现有如下区别:
for (double element : a) {
long bits = Double.doubleToLongBits(element);
result = 31 * result + (int)(bits ^ (bits >>> 32));
} 其中Object[]的实现有如下区别:
for (Object element : a)
result = 31 * result + (element == null ? 0 : element.hashCode()); 8 toString
下面是对int[]类型进行转字符串的方法,此外以下类型都使用了类似的方法:long[]、short[]、char[]、byte[]、float[]、double[]、boolean[]和Object[]。
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(", ");
}
} 9 asList
@SafeVarargs
@SuppressWarnings("varargs")
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
} 其中ArrayList是java.util.Arrays.ArrayList。
10 小结
在实现集合框架的过程中,有调用Arrays的静态方法,因此笔者在这里对Arrays的相关方法进行了说明。

京公网安备 11010502036488号