java中的Arrays这个工具类你真的会用吗 (2)

分析: 主要还是调用了本地的方法arraycopy完成数组的指定长度拷贝,可以看到源码并没有对数组的长度进行检查,主要是arraycopy()这个方法时使了Math.min()方法,保证了你声明的长度在一个安全的范围之内,如果你拷贝的长度超出了数组的长度,就默认拷贝整个数组。至于native修饰的方法的使用,可以看看这里

System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength));

当然如果需要拷贝数组指定的区间 ,可以使用Arrays的 copyOfRange(int[] original, int from, int to) 实现原理和arraycopy()方法的原理类似:

@Test public void testCopy(){ int [] srcArray = {11,2,244,5,6,54}; // 拷贝指定范围的数组 int[] descArray = Arrays.copyOfRange(srcArray,0,3); System.out.println(Arrays.toString(descArray)); }

输出结果:

[11, 2, 244]

注: copyOfRange(int[] original, int from, int to)中的参数to是不包含在拷贝的结果中的,上述的例子,就只能拷贝到索引为2的元素,不包含索引为3的元素,这点需要注意。

3.4 equals方法

主要重写了Object类的equals方法,用来比较两个数组内容是否相等,也就是他们中的元素是否相等。

基本用法:

@Test public void equalTest(){ int[] array ={1,2,3,4}; int[] result ={1,2,3,4}; System.out.println(Arrays.equals(array,result)); System.out.println(array == result); }

结果:

true false

看源码之前,有必要讲一下重写了equals方法之后,两个对象比较的是值,也就是他们的内容,这点非常的重要。重写equals方法的注意事项可以移步这里。

源码如下:

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; }

源码说明如下:

源码判断了四次,分别是首地址比较,是否为空,以及长度的比较,最后对于数组的各个元素进行比较。

有必要说明下第一个判断,也就是首地址的比较。当我们声明一个数组变量时,这个变量就代表数组的首地址,看下面这个代码:

@Test public void equalTest(){ int[] array ={1,2,3,4}; System.out.println(array); }

结果:

[I@4f2410ac // [代表数组 I代表整数 @分隔符 后边内存地址十六进制

​ 这表示的是一个地址。还是因为在声明一个数组时,会在堆里面创建一块内存区域,但是这块内存区域相对于堆来说可能很小,不好找。为了方便查找,所以将数组内存中的首地址表示出来。虚拟机将地址传给变量名array。这也是引用类型,传的是地址,也就是理解成array指向内存地址(类似于家庭的地址),每次运行可能地址都不一样,因为虚拟机开辟的内存空间可能不一样。

理解了这个,那么a==a2就好理解了,如果两个数组内存地址都相同,那么两个数组的肯定是相等的。

还有我认为程序写的比较好的地方就是源码中对数组每个元素的比较,也就是下面这段代码;

for (int i=0; i<length; i++) if (a[i] != a2[i]) return false; return true;

使用a[i] != a2[i] 作为判断条件,就可以减少比较次数,提高了性能。试想一下如果这里是相等的比较,那每次都要遍历整个数组,如果数据量大了,无疑在性能上会慢很多。又一次感叹到源码的魅力。

3.5 排序相关的方法sort()和parallelSort()

Arrays 这个类中主要涉及了两种类型的排序方法串行 sort()和并行parallelSort()这两个方法,当然对象的排序和基本类型的排序也不太一样。这里还是以int[]类型的为例。进行说明。

首先比较两个方法的性能:

public final int UPPER_LIMIT = 0xffffff; final int ROUNDS = 10; final int INCREMENT = 5; final int INIT_SIZE = 1000; @Test public void sortAndParallelSortTest(){ // 构造不同容量的集合 for (int capacity = INIT_SIZE; capacity < UPPER_LIMIT ; capacity*= INCREMENT) { ArrayList<Integer> list = new ArrayList<>(capacity); for (int j = 0; j < capacity; j++) { list.add((int) (Math.random()*capacity)); } double avgTimeOfParallelSort = 0; double avgTimeOfSort = 0; for (int j = 0; j <= ROUNDS ; j++) { // 每次排序都打乱顺序 Collections.shuffle(list); Integer[] arr1 = list.toArray(new Integer[capacity]); Integer[] arr2 = arr1.clone(); avgTimeOfParallelSort += counter(arr1,true); avgTimeOfSort += counter(arr2, false); } // 输出结果 output(capacity,avgTimeOfParallelSort/ROUNDS,avgTimeOfSort/ROUNDS); } } private void output(int capacity, double v, double v1) { System.out.println("=======================测试排序的时间========="); System.out.println("Capacity"+capacity); System.out.println("ParallelSort"+v); System.out.println("Sort"+v1); System.out.println("比较快的排序是:"+(v < v1 ? "ParallelSort":"Sort")); } // 计算消耗的时间 private double counter(Integer[] arr1, boolean b) { long begin,end; begin = System.nanoTime(); if(b){ Arrays.parallelSort(arr1); }else{ Arrays.parallelSort(arr1); } end = System.nanoTime(); return BigDecimal.valueOf(end-begin,9).doubleValue(); }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zggwxs.html