有没有发现一些变化,哈哈哈~技术博客本身是很枯燥无味的,我以后将在每篇博客上加上一个banner,给技术博客增加一些生动色。
我前期的更博重心还是在技术实现和理解上,后面会抛出一些问题和项目实战技巧,详细的可以看我的更新计划:
https://blog.csdn.net/u014294681/article/details/85333095
Arrays是JDK1.2开始提供的一个工具类,在我们平时开发中,对数组排序,查找,拷贝,填充等各种处理,几乎都会使用到它。
但是如果只是会用,这不是我写博客的重点,我写博客喜欢分析它的实现原理。接下来我将带着大家来一起目睹下Arrays的风采。
目录:
- Arrays的排序
- Arrays的查找
- Arrays的拷贝
- Arrays的填充
- Arrays集合转换
- Arrays的其他方法
1. Arrays的排序
- 1.1 介绍
Arrays提供了对int,long,short,char,byte,float,double,Object,内比较器类型的数组的排序,同时也支持传入一个外比较器对数组进行排序。
- 1.2 API
public static void sort(int[] a)
public static void sort(int[] a, int fromIndex, int toIndex)
public static void sort(long[] a)
public static void sort(long[] a, int fromIndex, int toIndex)
public static void sort(short[] a)
public static void sort(short[] a, int fromIndex, int toIndex)
public static void sort(char[] a)
public static void sort(char[] a, int fromIndex, int toIndex)
public static void sort(byte[] a)
public static void sort(byte[] a, int fromIndex, int toIndex)
public static void sort(float[] a)
public static void sort(float[] a, int fromIndex, int toIndex)
public static void sort(double[] a)
public static void sort(double[] a, int fromIndex, int toIndex)
public static void parallelSort(byte[] a)
public static void parallelSort(byte[] a, int fromIndex, int toIndex)
public static void parallelSort(char[] a)
public static void parallelSort(char[] a, int fromIndex, int toIndex)
public static void parallelSort(short[] a)
public static void parallelSort(short[] a, int fromIndex, int toIndex)
public static void parallelSort(int[] a)
public static void parallelSort(int[] a, int fromIndex, int toIndex)
public static void parallelSort(long[] a)
public static void parallelSort(long[] a, int fromIndex, int toIndex)
public static void parallelSort(float[] a)
public static void parallelSort(float[] a, int fromIndex, int toIndex)
public static void parallelSort(double[] a)
public static void parallelSort(double[] a, int fromIndex, int toIndex)
public static <T extends Comparable<? super T>> void parallelSort(T[] a)
public static <T extends Comparable<? super T>>
void parallelSort(T[] a, int fromIndex, int toIndex)
public static <T> void parallelSort(T[] a, Comparator<? super T> cmp)
public static <T> void parallelSort(T[] a, int fromIndex, int toIndex,
Comparator<? super T> cmp)
public static void sort(Object[] a)
public static void sort(Object[] a, int fromIndex, int toIndex)
public static <T> void sort(T[] a, Comparator<? super T> c)
public static <T> void sort(T[] a, int fromIndex, int toIndex,
Comparator<? super T> c)
可以看到除了sort方法,还有parallelSort方法,这是JDK1.8之后提供的并行排序方法。
- 1.3 使用
这边的使用我只会抽出几个典型出来,如基本类型的sort,内比较器类型的sort,Object的sort,外比较器的sort,以及它们的parallelSort。原理分析也是一样,采用典型分析的方法。
public static void main(String[] args) {
// 基本数据类型
int[] array0 = newIntArray();
Arrays.sort(array0);
System.out.println("Arrays.sort(int[]) = " + Arrays.toString(array0));
// 指定索引范围的排序
int[] array1 = newIntArray();
Arrays.sort(array1, 0, 5);
System.out.println("Arrays.sort(int[], from, end) = " + Arrays.toString(array1));
// Object类型
Object[] objects = newObjectArray();
Arrays.sort(objects);
System.out.println("Arrays.sort(Object[]) = " + Arrays.toString(objects));
// 外比较器
String[] array2 = newStringArray();
Arrays.sort(array2, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o2.compareTo(o1);
}
});
System.out.println("Arrays.sort(T[] a, Comparator<? super T> c) = " + Arrays.toString(array2));
// 并行排序
int[] array3 = newIntArray();
Arrays.parallelSort(array3);
System.out.println("Arrays.parallelSort(int[]) = " + Arrays.toString(array3));
}
private static int[] newIntArray() {
return new int[] {9, 1, 3, 8, 0, 5, 4, 2, 7, 6};
}
private static Object[] newObjectArray() {
return new Object[] {"z", "3", "5", "2", "kk"};
}
private static String[] newStringArray() {
return new String[] {"z", "3", "5", "2", "kk"};
}
执行输出:
Arrays.sort(int[]) = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Arrays.sort(int[], from, end) = [0, 1, 3, 8, 9, 5, 4, 2, 7, 6]
Arrays.sort(Object[]) = [2, 3, 5, kk, z]
Arrays.sort(T[] a, Comparator<? super T> c) = [z, kk, 5, 3, 2]
Arrays.parallelSort(int[]) = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
- 1.4 实现原理
1.4.1 public static void sort(int[] a):
public static void sort(int[] a) {
DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0);
}
对于基本数据类型,使用的都是DualPivotQuicksort这个类进行排序,那么DualPivotQuicksort又是何方神圣?
我们都知道快排,先来复习下快排:
/**
* 快速排序,分治 + 递归.
* <p>
* 平均O(NlogN) | 最好O(NlogN) | 最坏O(N²) | 空间O(logN) - O(N²) | 不稳定
*
* @param array 待排序数组
*/
private static void quickSort(int array[]) {
long start = System.nanoTime();
quickSort(array, 0, array.length - 1);
System.out.println("quick sort cost = " + (System.nanoTime() - start) / 1000 + "ms "
+ Arrays.toString(array));
}
private static void quickSort(int array[], int left, int right) {
// 切记,一定要左边小于右边时才分部处理
if (left < right) {
// 找到一个基准位置p
int p = partation(array, left, right);
// 对左半部分递归快排
quickSort(array, left, p - 1);
// 对右半部分递归快排
quickSort(array, p + 1, right);
// 这边只有分治,没有合并,归并 = 分治 + 合并
}
}
/**
* 分而治之,找到划分基准,并交换.
*
* @param array 待排序数组
* @param left 起始位置
* @param right 结束位置
* @return 找到的基准位置
*/
private static int partation(int array[], int left, int right) {
// 以最左边的数为基准
int pv = array[left];
// 记录基准位置
int p = left;
// 往右遍历数组,如果小于基准,则与基准交换
for (int i = p + 1; i <= right; i++) {
if (array[i] < pv) {
// 基准前移
p++;
// 如果是基准位置的下一个位置,则不用交换
if (p != i) {
swap(array, p, i);
}
}
}
// 最后,将新的基准的值赋值给最左边
array[left] = array[p];
// 将基准赋值到中间,划分位置
array[p] = pv;
// 返回划分位置
return p;
}
快排采用的是分治+递归的思路,不断地找到基准值,时间复杂度为NlogN(O(1) < O(logn) < O(n) < O(nlogn) < O(n²)< O(n³) < O(2ⁿ) < O(n!)),可以说快排的性能算不错的了,JDK1.7之前用的都是快排,1.7之后开始使用DualPivotQuicksort。
Dual-Pivot
是俄罗斯人
Vladimir Yaroslavskiy
在2009年开发出来的。要知道经典快排在1990年代稳定下来就再也没有大改过了,几乎所有的语言里面的排序用的都是同样的经典快排的算法。20年之后当这个俄罗斯人提出新的
Dual-Pivot快排
的时候,很多人的第一想法是不信的,因为经典快排都被研究烂了,大家不相信在这个算法上面还会有什么可以改进的地方。
那么
Dual-Pivot快排
到底是怎么样的一个排序算法呢?其实从它的名字里面可以看出一些端倪:在经典快排里面有一个
pivot
的概念,它是用来分隔大数和小数的 -- 这个pivot把一个数组分成两份。那么所谓的Dual-Pivot其实就是用两个Pivot, 把整个数组分成三份,性能比经典快排更快。
关于DualPivotQuicksort的实现原理,感兴趣的同学可以看看这篇文章:https://www.cnblogs.com/chang4/p/9346012.html
1.4.2 public static void sort(Object[] a):
public static void sort(Object[] a) {
if (LegacyMergeSort.userRequested)
legacyMergeSort(a);
else
ComparableTimSort.sort(a, 0, a.length, null, 0, 0);
}
LegacyMergeSort是传统的归并排序,JDK1.7之前用的都是它。上面的排序有两个分支,如果用户设置了userRequested,则对Object[]数组的排序会使用传统的归并排序,否则使用ComparableTimSort(一种起源于归并排序和插入排序的混合排序算法)。
如果设置LegacyMergeSort.userRequested?
System.setProperty("java.util.Arrays.useLegacyMergeSort", "true");
复习下经典的归并排序:
/**
* 归并排序,分治 + 合并 + 递归.
*
* <p>
* 就是采用先 “分割” 再 “合并” 的思想。
* 我们首先把一个未排序的序列从中间分割成2部分,再把2部分分成4部分,依次分割下去,直到分割成一个一个的数据,
* 再把这些数据两两归并到一起,使之有序,不停的归并,最后成为一个排好序的序列。
* <p>
* <p>
* 分割到最小单元为1,再合并:
* <pre>
* ------------------------------------------------------------------------------------------
* 14 12 15 13 11 16
* | |
* 14 12 15 13 11 16
* -----------------------
* | |
* 14 12 15
* ----------- -----
* | | | 同左边一样分割再合并
* 14 12 15
* ---- ---- ----
* | |
* 12 14 15
* ----------- ----
* | |
* 12 14 15 11 13 16
* --------------- --------------
* |
* 11 12 13 14 15 16
* ------------------------------------------------------------------------------------------
* </pre>
*
* <p>
* 平均O(NlogN) | 最好O(NlogN) | 最坏O(NlogN) | 空间O(N) | 稳定
*
* @param array 待排序数组
*/
private static void mergeSort(int array[]) {
long start = System.nanoTime();
int len = array.length;
// 空间复杂度为O(N),需要构建一个同等大小的临时数组
int temp[] = new int[len];
mergeSort(array, temp, 0, len - 1);
System.out.println("merge sort cost = " + (System.nanoTime() - start) / 1000 + "ms "
+ Arrays.toString(array));
}
private static void mergeSort(int array[], int temp[], int left, int right) {
// 当左边小于右边,分治
if (left < right) {
// 不断从中间分割,使得左边 !< 右边,即不能再分割了
int mid = (left + right) / 2;
// 递归分治,先分治到最小
mergeSort(array, temp, left, mid);
mergeSort(array, temp, mid + 1, right);
// 再合并
merge(array, temp, left, mid, right);
}
}
/**
* 合并数据.
*
* @param array 数组
* @param temp 临时数组
* @param left left索引
* @param mid mid索引
* @param right right索引
*/
private static void merge(int array[], int temp[], int left, int mid, int right) {
// 从left到right拷贝一份数组
for (int i = left; i <= right; i++) {
temp[i] = array[i];
}
// 记录左右部分的索引,两段起始位置
int pa = left;
int pb = mid + 1;
// 合并后数组的索引
int index = left;
while (pa <= mid && pb <= right) {
// 哪一部分小,就拷贝哪一部分到新数组
if (temp[pa] <= temp[pb]) {
// 拷贝pa的
array[index++] = temp[pa++];
} else {
// 否则就拷贝pb的
array[index++] = temp[pb++];
}
}
// 处理没有拷贝完的部分,直接赋值到新数组
while (pa <= mid) {
array[index++] = temp[pa++];
}
while (pb <= right) {
array[index++] = temp[pb++];
}
}
核心思想:分治 + 合并 + 递归,时间复杂度为O(NlogN)。
而TimSort算法是一种起源于归并排序和插入排序的混合排序算法,设计初衷是为了在真实世界中的各种数据中可以有较好的性能。该算法最初是由Tim Peters于2002年在Python语言中提出的。
TimSort 是一个归并排序做了大量优化的版本。对归并排序排在已经反向排好序的输入时表现O(n2)的特点做了特别优化。对已经正向排好序的输入减少回溯。对两种情况混合(一会升序,一会降序)的输入处理比较好。
在jdk1.7之后,Arrays类中的sort方法有一个分支判断,当LegacyMergeSort.userRequested为true的情况下,采用legacyMergeSort,否则采用ComparableTimSort。并且在legacyMergeSort的注释上标明了该方法会在以后的jdk版本中废弃,因此以后Arrays类中的sort方法将采用ComparableTimSort类中的sort方法。对TimSort感兴趣的同学可以看看这篇文章:
https://blog.csdn.net/bruce_6/article/details/38299199
1.4.3 public static <T> void sort(T[] a, Comparator<? super T> c)
public static <T> void sort(T[] a, Comparator<? super T> c) {
if (c == null) {
sort(a);
} else {
if (LegacyMergeSort.userRequested)
legacyMergeSort(a, c);
else
TimSort.sort(a, 0, a.length, c, null, 0, 0);
}
}
和public static void sort(Object[] a)实现差不多,差别在于是否传入外部比较器。但是它里面有一个分支判断,如果传入的外比较器为空,则会走public static void sort(Object[] a)进行排序。
1.4.4 public static void parallelSort(int[] a)
public static void parallelSort(int[] a) {
int n = a.length, p, g;
if (n <= MIN_ARRAY_SORT_GRAN ||
(p = ForkJoinPool.getCommonPoolParallelism()) == 1)
DualPivotQuicksort.sort(a, 0, n - 1, null, 0, 0);
else
new ArraysParallelSortHelpers.FJInt.Sorter
(null, a, new int[n], 0, n, 0,
((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
MIN_ARRAY_SORT_GRAN : g).invoke();
}
当要排序的数组大小小于等于MIN_ARRAY_SORT_GRAN(1<<13 = 8192)或者只有一个执行线程的时候,那么使用双轴快排,和
public static void sort(int[] a)一样,否则使用并行排序。
2. Arrays的查找
- 2.1 介绍
Arrays提供了查找方法为二分查找,二分查找是经典的查找算法,对应的还有差值查找。查找算法有个前提,就是待查找的数组或者集合必须是有序的。
- 2.2 API
public static int binarySearch(long[] a, long key)
public static int binarySearch(long[] a, int fromIndex, int toIndex,
long key)
public static int binarySearch(int[] a, int key)
public static int binarySearch(int[] a, int fromIndex, int toIndex,
int key)
public static int binarySearch(short[] a, short key)
public static int binarySearch(short[] a, int fromIndex, int toIndex,
short key)
public static int binarySearch(char[] a, char key)
public static int binarySearch(char[] a, int fromIndex, int toIndex,
char key)
public static int binarySearch(byte[] a, byte key)
public static int binarySearch(byte[] a, int fromIndex, int toIndex,
byte key)
public static int binarySearch(double[] a, double key)
public static int binarySearch(double[] a, int fromIndex, int toIndex,
double key)
public static int binarySearch(float[] a, float key)
public static int binarySearch(float[] a, int fromIndex, int toIndex,
float key)
public static int binarySearch(Object[] a, Object key)
public static int binarySearch(Object[] a, int fromIndex, int toIndex,
Object key)
public static <T> int binarySearch(T[] a, T key, Comparator<? super T> c)
public static <T> int binarySearch(T[] a, int fromIndex, int toIndex,
T key, Comparator<? super T> c)
同样也是一堆API,支持基本数据类型数组,Object数组的二分查找,以及可以在查找时传入外部比较器。
- 2.3 使用
private static void testSearch() {
int[] array = new int[100];
for (int i = 0; i < 100; i++) {
array[i] = new Random().nextInt(100);
}
System.out.println("origin array = " + Arrays.toString(array));
System.out.println("binarySearch = " + Arrays.binarySearch(array, 15));
Arrays.sort(array);
System.out.println("sorted array = " + Arrays.toString(array));
System.out.println("binarySearch after sort = " + Arrays.binarySearch(array, 15));
}
执行输出:
origin array = [27, 71, 99, 36, 22, 7, 46, 47, 63, 9, 80, 25, 72, 0, 12, 65, 27, 44, 30, 71, 39, 61, 35, 67, 65, 17, 73, 59, 41, 52, 31, 78, 19, 43, 65, 87, 57, 48, 5, 2, 93, 98, 80, 82, 13, 50, 96, 25, 25, 21, 82, 84, 59, 80, 14, 97, 0, 19, 93, 69, 68, 69, 5, 99, 64, 62, 59, 23, 83, 80, 36, 25, 44, 89, 6, 80, 29, 71, 42, 93, 81, 57, 18, 32, 14, 81, 83, 5, 83, 15, 51, 41, 90, 91, 53, 20, 92, 86, 15, 98]
binarySearch = -7
sorted array = [0, 0, 2, 5, 5, 5, 6, 7, 9, 12, 13, 14, 14, 15, 15, 17, 18, 19, 19, 20, 21, 22, 23, 25, 25, 25, 25, 27, 27, 29, 30, 31, 32, 35, 36, 36, 39, 41, 41, 42, 43, 44, 44, 46, 47, 48, 50, 51, 52, 53, 57, 57, 59, 59, 59, 61, 62, 63, 64, 65, 65, 65, 67, 68, 69, 69, 71, 71, 71, 72, 73, 78, 80, 80, 80, 80, 80, 81, 81, 82, 82, 83, 83, 83, 84, 86, 87, 89, 90, 91, 92, 93, 93, 93, 96, 97, 98, 98, 99, 99]
binarySearch after sort = 14
可以看到,未排序的数组,使用二分查找,下标显示不准,所以查找算法应该在有序数组中进行。
- 2.4 实现原理
查找算法的实现原理就简单多了,就是二分查找:
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.
}
3. Arrays的拷贝
- 3.1 介绍
Arrays提供了很多把一个源数组复制到目标数据的方法,包括可以指定复制的范围。核心实现还是System.arraycopy(),System.arraycopy是native方法,性能比较好。但是在Arrays的copy方法中大量使用了Math.min,这个函数会影响拷贝性能。
不过Arrays的方便之处是提供了各种类型的拷贝,包括基本数据类型和Object以及泛型。而且不用自己创建目标数组,Arrays的copy方法会直接返回目标数组。
- 3.2 API
public static <T> T[] copyOf(T[] original, int newLength)
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType)
public static byte[] copyOf(byte[] original, int newLength)
public static short[] copyOf(short[] original, int newLength)
public static int[] copyOf(int[] original, int newLength)
public static long[] copyOf(long[] original, int newLength)
public static char[] copyOf(char[] original, int newLength)
public static float[] copyOf(float[] original, int newLength)
public static double[] copyOf(double[] original, int newLength)
public static boolean[] copyOf(boolean[] original, int newLength)
public static <T> T[] copyOfRange(T[] original, int from, int to)
public static <T,U> T[] copyOfRange(U[] original, int from, int to, Class<? extends T[]> newType)
public static byte[] copyOfRange(byte[] original, int from, int to)
public static short[] copyOfRange(short[] original, int from, int to)
public static int[] copyOfRange(int[] original, int from, int to)
public static long[] copyOfRange(long[] original, int from, int to)
public static char[] copyOfRange(char[] original, int from, int to)
public static float[] copyOfRange(float[] original, int from, int to)
public static double[] copyOfRange(double[] original, int from, int to)
public static boolean[] copyOfRange(boolean[] original, int from, int to)
- 3.3 使用
private static void testCopy() {
int[] array = new int[] {1, 2, 3, 4, 5, 6, 7, 8};
int[] array1 = Arrays.copyOf(array, 5);
System.out.println(Arrays.toString(array1));
}
执行输出:
[1, 2, 3, 4, 5]
可以看到只要传入源数组,新数组的长度,就能得到拷贝后的目标数组。而不需要像System.arraycopy()得自己创建目标数组,其实就是包装了一层,方便开发者调用。
- 3.4 实现原理
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;
}
先创建目标数组,然后执行System.arraycopy的拷贝。
看看这段测试代码的性能对比:
private static void testCopy() {
int[] array = new int[] {1, 2, 3, 4, 5, 6, 7, 8};
long start = System.nanoTime();
int[] array1 = Arrays.copyOf(array, 5);
System.out.println(Arrays.toString(array1) + " - cost = " + (System.nanoTime() - start));
int[] array2 = new int[5];
start = System.nanoTime();
System.arraycopy(array, 0, array2, 0,
Math.min(array.length, 5));
System.out.println(Arrays.toString(array2) + " - cost = " + (System.nanoTime() - start));
}
执行输出:
[1, 2, 3, 4, 5] - cost = 253207
[1, 2, 3, 4, 5] - cost = 43907
Arrays的拷贝方法主要慢在Math.min方法。
4. Arrays的填充
- 4.1 介绍
Arrays的填充方法主要是把数组的每一个元素赋值成目标值。
- 4.2 API
public static void fill(long[] a, long val)
public static void fill(long[] a, int fromIndex, int toIndex, long val)
public static void fill(int[] a, int val)
public static void fill(int[] a, int fromIndex, int toIndex, int val)
public static void fill(short[] a, short val)
public static void fill(short[] a, int fromIndex, int toIndex, short val)
public static void fill(char[] a, char val)
public static void fill(char[] a, int fromIndex, int toIndex, char val)
public static void fill(byte[] a, byte val)
public static void fill(byte[] a, int fromIndex, int toIndex, byte val)
public static void fill(boolean[] a, boolean val)
public static void fill(boolean[] a, int fromIndex, int toIndex,
boolean val)
public static void fill(double[] a, double val)
public static void fill(double[] a, int fromIndex, int toIndex,double val)
public static void fill(float[] a, float val)
public static void fill(float[] a, int fromIndex, int toIndex, float val)
public static void fill(Object[] a, Object val)
public static void fill(Object[] a, int fromIndex, int toIndex, Object val)
- 4.3 使用
我在公司项目的一款区块链钱包中有一个小需求,就是钱包地址(16进制)在一些列表里不需要全部显示,中间显示成...。
为此我写了一个方法:
public static String getDisplayAddress(String address, int maxDisplay) throws IllegalArgumentException {
if (address == null || address.length() == 0)
return "";
if (maxDisplay < 3)
throw new IllegalArgumentException("maxDisplay must be > 3");
if (address.length() > maxDisplay) {
char[] origin = address.toCharArray();
char[] display = new char[maxDisplay];
Arrays.fill(display, '.');
int binary = maxDisplay >> 1;
System.arraycopy(origin, 0, display, 0, binary);
int limit = maxDisplay - binary - 3;
System.arraycopy(origin, origin.length - limit, display, binary + 3, limit);
return new String(display);
} else {
return address;
}
}
比如待处理的地址为0x9337d28ae702616abca62f01b7b90fd278bec830,处理完后为0x9337d...ec830
- 4.4 实现原理
原理很简单,就是一个循环,然后赋值。
public static void fill(char[] a, char val) {
for (int i = 0, len = a.length; i < len; i++)
a[i] = val;
}
5. Arrays集合转换
这个很简单,就不分那么细了,就是将一个数组转换成对应类型的集合,源码如下:
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
}
看看一个例子:
private static void testAsList() {
String[] strings = new String[] {"a", "b", "c", "d", "e"};
List<String> list = Arrays.asList(strings);
System.out.println(Arrays.toString(list.toArray()));
}
执行输出:[a, b, c, d, e]
6. Arrays的其他方法
Arrays还提供了其他有用的方法:
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(", ");
}
}
public static boolean deepEquals(Object[] a1, Object[] a2) {
if (a1 == a2)
return true;
if (a1 == null || a2==null)
return false;
int length = a1.length;
if (a2.length != length)
return false;
for (int i = 0; i < length; i++) {
Object e1 = a1[i];
Object e2 = a2[i];
if (e1 == e2)
continue;
if (e1 == null)
return false;
// Figure out whether the two elements are equal
boolean eq = deepEquals0(e1, e2);
if (!eq)
return false;
}
return true;
}
public static int hashCode(Object a[]) {
if (a == null)
return 0;
int result = 1;
for (Object element : a)
result = 31 * result + (element == null ? 0 : element.hashCode());
return result;
}
感兴趣的同学可以自己去看看。