天天看点

Java篇 - Arrays的使用和实现

Java篇 - Arrays的使用和实现

有没有发现一些变化,哈哈哈~技术博客本身是很枯燥无味的,我以后将在每篇博客上加上一个banner,给技术博客增加一些生动色。

我前期的更博重心还是在技术实现和理解上,后面会抛出一些问题和项目实战技巧,详细的可以看我的更新计划:

https://blog.csdn.net/u014294681/article/details/85333095

Arrays是JDK1.2开始提供的一个工具类,在我们平时开发中,对数组排序,查找,拷贝,填充等各种处理,几乎都会使用到它。

但是如果只是会用,这不是我写博客的重点,我写博客喜欢分析它的实现原理。接下来我将带着大家来一起目睹下Arrays的风采。

目录:

  1. Arrays的排序
  2. Arrays的查找
  3. Arrays的拷贝
  4. Arrays的填充
  5. Arrays集合转换
  6. 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;
    }
           

感兴趣的同学可以自己去看看。