JDK1.8源码解读之 Arrays

224 阅读18分钟

前言

  • 该类具有特别多的方法,但是很多都是重载方法。所以仅解读部分方法。
  • 此类包含用于操纵数组的各种方法(例如排序和搜索)。此类还包含一个静态工厂,该工厂允许将数组视为列表。
  • 如果指定的数组引用为null,则除非另有说明,否则此类中的方法都抛出{@code NullPointerException}。
  • 此类中所包含方法的文档包括对实现的简要说明。
  • 此类描述应被视为实现说明,而不是说明书的一部分。
  • 只要遵守规范本身,实现者就可以随意替换其他算法。

源码


package java.util;

public class Arrays {

    /**
     * 最小数组长度,低于该最小数组长度,并行排序算法将不会进一步划分排序任务。
     * 使用较小的大小通常会导致跨任务的内存争用,从而导致并行加速的可能性不大。
     */
    private static final int MIN_ARRAY_SORT_GRAN = 1 << 13;

    private Arrays() {}

    /**
     * 一个比较器,实现一组相互可比较的元素的自然排序。
     * 当提供的比较器为null时可以使用。
     * 为了简化基础实现中的代码共享,compare方法仅将Object类型声明为其第二个参数。
     * 数组类实现者注意:与该比较器一起使用的TimSort相比,ComparableTimSort是否提供任何性能优势是一个经验问题。
     * 如果没有,最好删除或绕过ComparableTimSort。
     * 当前没有经验性的案例可以将它们分开进行并行排序,因此所有公共Object parallelSort方法都使用相同的基于比较器的实现。
     */
    static final class NaturalOrder implements Comparator<Object> {
        @SuppressWarnings("unchecked")
        public int compare(Object first, Object second) {
            return ((Comparable<Object>)first).compareTo(second);
        }
        static final NaturalOrder INSTANCE = new NaturalOrder();
    }

    /**
     * 检查{@code fromIndex}和{@code toIndex}在范围内,如果不在范围内,则抛出异常。
     *
     */
    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);
        }
    }


    /**
     * 将指定的数组按升序排序。
     * 实施说明:排序算法是Vladimir Yaroslavskiy,Jon Bentley和Joshua Bloch编写的Dual-Pivot Quicksort。
     * 该算法可在许多数据集上提供O(n log(n))性能,从而导致其他快速排序降级为二次性能,并且通常比传统的(单轴)Quicksort实现要快。
     */
    public static void sort(int[] a) {
        DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0);
    }
    /**
     *
     * 省略各种sort方法
     */
    
    /**
     * 将指定的数组按升序排序。
     * 排序算法是一个并行的排序合并,它将数组分解为子数组,这些子数组本身经过排序然后合并。
     * 当子数组的长度达到最小粒度时,将使用适当的{@link Arrays#sort(byte [])Arrays.sort}方法对子数组进行排序。
     * 如果指定数组的长度小于最小粒度,则使用适当的{@link Arrays#sort(byte [])Arrays.sort}方法对其进行排序。
     * 该算法需要的工作空间不大于原始数组的大小。
     * {@link ForkJoinPool#commonPool()ForkJoin公共池}用于执行任何并行任务。
     *
     * @param a the array to be sorted
     *
     * @since 1.8
     */
    public static void parallelSort(byte[] a) {
        int n = a.length, p, g;
        if (n <= MIN_ARRAY_SORT_GRAN ||
            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
            DualPivotQuicksort.sort(a, 0, n - 1);
        else
            new ArraysParallelSortHelpers.FJByte.Sorter
                (null, a, new byte[n], 0, n, 0,
                 ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
                 MIN_ARRAY_SORT_GRAN : g).invoke();
    }


    /*
     * 省略各种parallelSort方法
     */

    /**
     * 可以使用系统属性选择旧的合并排序实现(以与损坏的比较器兼容)。由于循环依赖性,在封闭的类中不能为静态布尔值。在将来的版本中将其删除。 
     */
    static final class LegacyMergeSort {
        private static final boolean userRequested =
            java.security.AccessController.doPrivileged(
                new sun.security.action.GetBooleanAction(
                    "java.util.Arrays.useLegacyMergeSort")).booleanValue();
    }

    /**
     * 根据其元素的{@linkplain可比自然排序}将指定的对象数组按升序排序。
     * 数组中的所有元素必须实现{@link Comparable}接口。
     * 此外,数组中的所有元素都必须相互可比(即,{@code e1.compareTo(e2)}不得对元素中的任何元素{@code e1}和{@code e2}抛出{@code ClassCastException}数组)。
     * 这样的排序保证是稳定的:相等的元素不会由于排序而重新排序。
     *
     * 实施注意事项:此实现是一种稳定的,自适应的迭代合并排序,在对输入数组进行部分排序时,所需的比较少于n lg(n),
     * 而在对输入数组进行随机排序时提供传统的合并排序的性能。如果输入数组几乎已排序,则该实现需要大约n个比较。
     * 临时存储要求从几乎排序的输入数组的小常数到随机排序的输入数组的n /2对象引用,不等。
     * 该实现在其输入数组中充分利用了升序和降序,并且可以在同一输入数组的不同部分中利用了升序和降序。
     * 它非常适合合并两个或多个排序后的数组:简单地将数组连接起来并对结果数组进行排序。
     */
    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) {
        Object[] aux = a.clone();
        mergeSort(aux, a, 0, a.length, 0);
    }

    /**
     * 根据对象元素的{@linkplain可比自然排序},将指定对象数组的指定范围按升序排序。
     * 要排序的范围从索引{@code fromIndex}到索引{@code toIndex}不包括在内。
     * (如果{@code fromIndex == toIndex},则要排序的范围为空。)
     * 此范围内的所有元素都必须实现{@link Comparable}接口。此外,此范围内的所有元素都必须相互可比较
     * (也就是说,{@code e1.compareTo(e2)}不得为元素中的任何元素{@code e1}和{@code e2}
     * 抛出{@code ClassCastException}数组)。
     * 这样的排序保证是稳定的:相等的元素不会由于排序而重新排序。
     * 实施注意事项:此实现是一种稳定的,自适应的迭代合并排序,在对输入数组进行部分排序时,所需的比较少于n lg(n),
     * 而在对输入数组进行随机排序时提供传统的合并排序的性能。如果输入数组几乎已排序,则该实现需要大约n个比较。
     * 临时存储要求从几乎排序的输入数组的小常数到随机排序的输入数组的n /2对象引用,不等。
     * 该实现在其输入数组中充分利用了升序和降序,并且可以在同一输入数组的不同部分中利用了升序和降序。
     * 它非常适合合并两个或多个排序后的数组:简单地将数组连接起来并对结果数组进行排序。
     */
    public static void sort(Object[] a, int fromIndex, int toIndex) {
        rangeCheck(a.length, fromIndex, toIndex);
        if (LegacyMergeSort.userRequested)
            legacyMergeSort(a, fromIndex, toIndex);
        else
            ComparableTimSort.sort(a, fromIndex, toIndex, 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);
    }

    private static final int INSERTIONSORT_THRESHOLD = 7;

    @SuppressWarnings({"unchecked", "rawtypes"})
    private static void mergeSort(Object[] src,
                                  Object[] dest,
                                  int low,
                                  int high,
                                  int off) {
        int length = high - low;

        if (length < INSERTIONSORT_THRESHOLD) {
            for (int i=low; i<high; i++)
                for (int j=i; j>low &&
                         ((Comparable) dest[j-1]).compareTo(dest[j])>0; j--)
                    swap(dest, j, j-1);
            return;
        }

        int destLow  = low;
        int destHigh = high;
        low  += off;
        high += off;
        int mid = (low + high) >>> 1;
        mergeSort(dest, src, low, mid, -off);
        mergeSort(dest, src, mid, high, -off);

        if (((Comparable)src[mid-1]).compareTo(src[mid]) <= 0) {
            System.arraycopy(src, low, dest, destLow, length);
            return;
        }

        for(int i = destLow, p = low, q = mid; i < destHigh; i++) {
            if (q >= high || p < mid && ((Comparable)src[p]).compareTo(src[q])<=0)
                dest[i] = src[p++];
            else
                dest[i] = src[q++];
        }
    }

    private static void swap(Object[] x, int a, int b) {
        Object t = x[a];
        x[a] = x[b];
        x[b] = t;
    }

    /**
     * 根据指定比较器引起的顺序对指定对象数组进行排序。
     * 数组中的所有元素都必须由指定的比较器相互比较
     * (也就是说,对于任何元素{@code e1}和{@code,{@ code c.compare(e1,e2)}
     * 都不得抛出{@code ClassCastException} e2})。
     * 这样的排序保证是稳定的:相等的元素不会由于排序而重新排序。
     * 实施注意事项:此实现是一种稳定的,自适应的迭代合并排序,在对输入数组进行部分排序时,所需的比较少于n lg(n),
     * 而在对输入数组进行随机排序时提供传统的合并排序的性能。
     * 如果输入数组几乎已排序,则该实现需要大约n个比较。
     * 临时存储要求从几乎排序的输入数组的小常数到随机排序的输入数组的n /2对象引用,不等。
     * 该实现在其输入数组中充分利用了升序和降序,并且可以在同一输入数组的不同部分中利用了升序和降序。
     * 它非常适合合并两个或多个排序后的数组:简单地将数组连接起来并对结果数组进行排序。
     *
     */
    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);
        }
    }

    /** To be removed in a future release. */
    private static <T> void legacyMergeSort(T[] a, Comparator<? super T> c) {
        T[] aux = a.clone();
        if (c==null)
            mergeSort(aux, a, 0, a.length, 0);
        else
            mergeSort(aux, a, 0, a.length, 0, c);
    }

    public static <T> void sort(T[] a, int fromIndex, int toIndex,
                                Comparator<? super T> c) {
        if (c == null) {
            sort(a, fromIndex, toIndex);
        } else {
            rangeCheck(a.length, fromIndex, toIndex);
            if (LegacyMergeSort.userRequested)
                legacyMergeSort(a, fromIndex, toIndex, c);
            else
                TimSort.sort(a, fromIndex, toIndex, c, null, 0, 0);
        }
    }

    /** To be removed in a future release. */
    private static <T> void legacyMergeSort(T[] a, int fromIndex, int toIndex,
                                            Comparator<? super T> c) {
        T[] aux = copyOfRange(a, fromIndex, toIndex);
        if (c==null)
            mergeSort(aux, a, fromIndex, toIndex, -fromIndex);
        else
            mergeSort(aux, a, fromIndex, toIndex, -fromIndex, c);
    }

    /**
     * Src is the source array that starts at index 0
     * Dest is the (possibly larger) array destination with a possible offset
     * low is the index in dest to start sorting
     * high is the end index in dest to end sorting
     * off is the offset into src corresponding to low in dest
     * To be removed in a future release.
     */
    @SuppressWarnings({"rawtypes", "unchecked"})
    private static void mergeSort(Object[] src,
                                  Object[] dest,
                                  int low, int high, int off,
                                  Comparator c) {
        int length = high - low;

        // Insertion sort on smallest arrays
        if (length < INSERTIONSORT_THRESHOLD) {
            for (int i=low; i<high; i++)
                for (int j=i; j>low && c.compare(dest[j-1], dest[j])>0; j--)
                    swap(dest, j, j-1);
            return;
        }

        // Recursively sort halves of dest into src
        int destLow  = low;
        int destHigh = high;
        low  += off;
        high += off;
        int mid = (low + high) >>> 1;
        mergeSort(dest, src, low, mid, -off, c);
        mergeSort(dest, src, mid, high, -off, c);

        // If list is already sorted, just copy from src to dest.  This is an
        // optimization that results in faster sorts for nearly ordered lists.
        if (c.compare(src[mid-1], src[mid]) <= 0) {
           System.arraycopy(src, low, dest, destLow, length);
           return;
        }

        // Merge sorted halves (now in src) into dest
        for(int i = destLow, p = low, q = mid; i < destHigh; i++) {
            if (q >= high || p < mid && c.compare(src[p], src[q]) <= 0)
                dest[i] = src[p++];
            else
                dest[i] = src[q++];
        }
    }


    /**
     * 使用提供的函数并行地将给定数组的每个元素累积到位。
     * 例如,如果数组最初保存{@code [2,1,0,3]},并且该操作执行加法,
     * 则返回时,数组保存{@code [2,3,3,6]}。对于大型数组,并行前缀计算通常比顺序循环更有效。
     */
    public static <T> void parallelPrefix(T[] array, BinaryOperator<T> op) {
        Objects.requireNonNull(op);
        if (array.length > 0)
            new ArrayPrefixHelpers.CumulateTask<>
                    (null, op, array, 0, array.length).invoke();
    }
    // 省略各种parallelPrefix方法。

    /**
     * 使用二进制搜索算法在指定的long型数组中搜索指定的值。
     * 在进行此调用之前,必须对数组进行排序(例如,通过{@link #sort(long [])}方法)。
     * 如果未排序,则结果不确定。如果数组包含具有指定值的多个元素,则不能保证将找到哪个元素。
     */
    public static int binarySearch(long[] a, long key) {
        return binarySearch0(a, 0, a.length, key);
    }

    public static int binarySearch(long[] a, int fromIndex, int toIndex,
                                   long key) {
        rangeCheck(a.length, fromIndex, toIndex);
        return binarySearch0(a, fromIndex, toIndex, key);
    }

    // 省略各种binarySearch 方法。


    /**
     * 如果两个指定的long数组彼此相等,则返回true。
     * 如果两个数组包含相同数量的元素,并且两个数组中所有对应的元素对均相等,则认为两个数组相等。
     * 换句话说,如果两个数组包含相同顺序的相同元素,则它们相等。
     * 另外,如果两个数组引用都为空,则认为它们相等。
     *
     */
    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;
    }
    // 省略各种equals方法

    // Filling

    /**
     * 将指定的long值分配给指定的long数组的每个元素。
     */
    public static void fill(long[] a, long val) {
        for (int i = 0, len = a.length; i < len; i++)
            a[i] = val;
    }
    // 省略各种fill方法。

    /**
     * 复制指定的数组,截断或填充为空(如果需要),以便副本具有指定的长度。
     * 对于在原始数组和副本中均有效的所有索引,两个数组将包含相同的值。
     * 对于副本中有效但原始索引无效的任何索引,副本将包含null。
     * 当且仅当指定长度大于原始数组的长度时,此类索引才会存在。所得数组与原始数组完全相同。
     */
    @SuppressWarnings("unchecked")
    public static <T> T[] copyOf(T[] original, int newLength) {
        return (T[]) copyOf(original, newLength, original.getClass());
    }
    // 省略各种copyOf方法。
    
    /**
     * 将指定数组的指定范围复制到新数组中。
     * 范围的起始索引(从)必须介于零和original.length(含)之间。
     * original [from]处的值放置在副本的初始元素中(除非from == original.length或from == to)。
     * 来自原始数组中后续元素的值将放入副本中的后续元素中。
     * 范围(to)的最终索引(必须大于或等于from)可以大于original.length,在这种情况下,
     * 会将空值放在索引大于或等于原始值的副本的所有元素中。
     * 长度-从。返回数组的长度将为--from。所得数组与原始数组完全相同。
     */
    @SuppressWarnings("unchecked")
    public static <T> T[] copyOfRange(T[] original, int from, int to) {
        return copyOfRange(original, from, to, (Class<? extends T[]>) original.getClass());
    }
    // 省略各种copyOfRange方法。

    /**
     * 返回由指定数组支持的固定大小的列表。
     * (更改为返回列表,将其“写入”到数组。)
     * 与{@link Collection#toArray}结合使用,此方法充当基于数组的API和基于集合的API之间的桥梁。
     * 返回的列表是可序列化的,并且实现了{@link RandomAccess}。
     */
    @SafeVarargs
    @SuppressWarnings("varargs")
    public static <T> List<T> asList(T... a) {
        return new ArrayList<>(a);
    }

    private static class ArrayList<E> extends AbstractList<E>
        implements RandomAccess, java.io.Serializable
    {
        private static final long serialVersionUID = -2764017481108945198L;
        private final E[] a;

        ArrayList(E[] array) {
            a = Objects.requireNonNull(array);
        }

        @Override
        public int size() {
            return a.length;
        }

        @Override
        public Object[] toArray() {
            return a.clone();
        }

        @Override
        @SuppressWarnings("unchecked")
        public <T> T[] toArray(T[] a) {
            int size = size();
            if (a.length < size)
                return Arrays.copyOf(this.a, size,
                                     (Class<? extends T[]>) a.getClass());
            System.arraycopy(this.a, 0, a, 0, size);
            if (a.length > size)
                a[size] = null;
            return a;
        }

        @Override
        public E get(int index) {
            return a[index];
        }

        @Override
        public E set(int index, E element) {
            E oldValue = a[index];
            a[index] = element;
            return oldValue;
        }

        @Override
        public int indexOf(Object o) {
            E[] a = this.a;
            if (o == null) {
                for (int i = 0; i < a.length; i++)
                    if (a[i] == null)
                        return i;
            } else {
                for (int i = 0; i < a.length; i++)
                    if (o.equals(a[i]))
                        return i;
            }
            return -1;
        }

        @Override
        public boolean contains(Object o) {
            return indexOf(o) != -1;
        }

        @Override
        public Spliterator<E> spliterator() {
            return Spliterators.spliterator(a, Spliterator.ORDERED);
        }

        @Override
        public void forEach(Consumer<? super E> action) {
            Objects.requireNonNull(action);
            for (E e : a) {
                action.accept(e);
            }
        }

        @Override
        public void replaceAll(UnaryOperator<E> operator) {
            Objects.requireNonNull(operator);
            E[] a = this.a;
            for (int i = 0; i < a.length; i++) {
                a[i] = operator.apply(a[i]);
            }
        }

        @Override
        public void sort(Comparator<? super E> c) {
            Arrays.sort(a, c);
        }
    }

    /**
     * 根据指定数组的内容返回哈希码。
     * 对于诸如Arrays.equals(a,b)的任意两个长数组a和b,
     * Arrays.hashCode(a)== Arrays.hashCode(b)也是这种情况。
     * 此方法返回的值与在包含一系列{@link Long}实例的{@link List}实例上以相同的顺序调用{@link List#hashCode()hashCode}方法所获得的值相同。
     * 如果a为null,则此方法返回0。
     */
    public static int hashCode(long a[]) {
        if (a == null)
            return 0;

        int result = 1;
        for (long element : a) {
            int elementHash = (int)(element ^ (element >>> 32));
            result = 31 * result + elementHash;
        }

        return result;
    }
    // 省略各种hashCode()方法

    /**
     * 根据指定数组的“深层内容”返回哈希码。如果数组包含其他数组作为元素,则哈希码基于其内容,等等。
     * 因此,不能直接或间接通过一个或多个级别的数组在包含自身作为元素的数组上调用此方法。
     * 此类调用的行为是不确定的。
     */
    public static int deepHashCode(Object a[]) {
        if (a == null)
            return 0;

        int result = 1;

        for (Object element : a) {
            int elementHash = 0;
            if (element instanceof Object[])
                elementHash = deepHashCode((Object[]) element);
            else if (element instanceof byte[])
                elementHash = hashCode((byte[]) element);
            else if (element instanceof short[])
                elementHash = hashCode((short[]) element);
            else if (element instanceof int[])
                elementHash = hashCode((int[]) element);
            else if (element instanceof long[])
                elementHash = hashCode((long[]) element);
            else if (element instanceof char[])
                elementHash = hashCode((char[]) element);
            else if (element instanceof float[])
                elementHash = hashCode((float[]) element);
            else if (element instanceof double[])
                elementHash = hashCode((double[]) element);
            else if (element instanceof boolean[])
                elementHash = hashCode((boolean[]) element);
            else if (element != null)
                elementHash = element.hashCode();

            result = 31 * result + elementHash;
        }

        return result;
    }

    /**
     * 如果两个指定的数组彼此深度相等,则返回true。
     * 与{@link #equals(Object [],Object [])}方法不同,此方法适用于任意深度的嵌套数组。
     * 如果两个数组引用都为null,或者两个数组引用都引用了包含相同数量元素的数组,
     * 并且两个数组中所有对应的元素对都非常相等,则认为它们是完全相等的。
     * 如果满足以下任一条件,则两个可能为null的元素e1和e2完全相等:
     * 1 e1和e2都是对象引用类型的数组,而Arrays.deepEquals(e1,e2)将返回true
     * 2 e1和e2是相同基元的数组类型,并且Arrays.equals(e1,e2)的适当重载将返回true。
     * 3 e1 == e2
     * 4 e1.equals(e2)将返回true。
     * 请注意,此定义允许在任何深度使用null元素。
     * 如果任何指定的数组通过一个或多个级别的数组直接或间接包含自身作为元素,则此方法的行为未定义。
     */
    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;
    }

    static boolean deepEquals0(Object e1, Object e2) {
        assert e1 != null;
        boolean eq;
        if (e1 instanceof Object[] && e2 instanceof Object[])
            eq = deepEquals ((Object[]) e1, (Object[]) e2);
        else if (e1 instanceof byte[] && e2 instanceof byte[])
            eq = equals((byte[]) e1, (byte[]) e2);
        else if (e1 instanceof short[] && e2 instanceof short[])
            eq = equals((short[]) e1, (short[]) e2);
        else if (e1 instanceof int[] && e2 instanceof int[])
            eq = equals((int[]) e1, (int[]) e2);
        else if (e1 instanceof long[] && e2 instanceof long[])
            eq = equals((long[]) e1, (long[]) e2);
        else if (e1 instanceof char[] && e2 instanceof char[])
            eq = equals((char[]) e1, (char[]) e2);
        else if (e1 instanceof float[] && e2 instanceof float[])
            eq = equals((float[]) e1, (float[]) e2);
        else if (e1 instanceof double[] && e2 instanceof double[])
            eq = equals((double[]) e1, (double[]) e2);
        else if (e1 instanceof boolean[] && e2 instanceof boolean[])
            eq = equals((boolean[]) e1, (boolean[]) e2);
        else
            eq = e1.equals(e2);
        return eq;
    }

    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(", ");
        }
    }
    // 省略各种toString方法。
    
    /**
     * 返回指定数组的“深层内容”的字符串表示形式。
     * 如果数组包含其他数组作为元素,则字符串表示形式包含其内容,依此类推。
     * 此方法旨在将多维数组转换为字符串。
     * 字符串表示形式由数组元素列表组成,并用方括号(“ []”)括起来。
     * 相邻元素由字符“,”(逗号后跟空格)分隔。
     * 元素通过String.valueOf(Object)转换为字符串,除非它们本身是数组。
     * 如果元素e是原始类型的数组,则通过调用Arrays.toString(e)的适当重载将其转换为字符串。
     * 如果元素e是引用类型的数组,则通过递归调用此方法将其转换为字符串。
     * 为避免无限递归,如果指定的数组包含自身作为元素,
     * 或通过一个或多个级别的数组包含对自身的间接引用,
     * 则自引用将转换为字符串“ [...]”。
     * 例如,仅包含对自身的引用的数组将呈现为“ [[...]]”。
     * 如果指定的数组为null,则此方法返回“ null”。
     */
    public static String deepToString(Object[] a) {
        if (a == null)
            return "null";

        int bufLen = 20 * a.length;
        if (a.length != 0 && bufLen <= 0)
            bufLen = Integer.MAX_VALUE;
        StringBuilder buf = new StringBuilder(bufLen);
        deepToString(a, buf, new HashSet<Object[]>());
        return buf.toString();
    }

    private static void deepToString(Object[] a, StringBuilder buf,
                                     Set<Object[]> dejaVu) {
        if (a == null) {
            buf.append("null");
            return;
        }
        int iMax = a.length - 1;
        if (iMax == -1) {
            buf.append("[]");
            return;
        }

        dejaVu.add(a);
        buf.append('[');
        for (int i = 0; ; i++) {

            Object element = a[i];
            if (element == null) {
                buf.append("null");
            } else {
                Class<?> eClass = element.getClass();

                if (eClass.isArray()) {
                    if (eClass == byte[].class)
                        buf.append(toString((byte[]) element));
                    else if (eClass == short[].class)
                        buf.append(toString((short[]) element));
                    else if (eClass == int[].class)
                        buf.append(toString((int[]) element));
                    else if (eClass == long[].class)
                        buf.append(toString((long[]) element));
                    else if (eClass == char[].class)
                        buf.append(toString((char[]) element));
                    else if (eClass == float[].class)
                        buf.append(toString((float[]) element));
                    else if (eClass == double[].class)
                        buf.append(toString((double[]) element));
                    else if (eClass == boolean[].class)
                        buf.append(toString((boolean[]) element));
                    else { // element is an array of object references
                        if (dejaVu.contains(element))
                            buf.append("[...]");
                        else
                            deepToString((Object[])element, buf, dejaVu);
                    }
                } else {  // element is non-null and not an array
                    buf.append(element.toString());
                }
            }
            if (i == iMax)
                break;
            buf.append(", ");
        }
        buf.append(']');
        dejaVu.remove(a);
    }


    /**
     * 使用提供的生成器函数来计算每个元素,设置指定数组的所有元素。
     * 如果生成器函数引发异常,它将被中继到调用者,并且数组将处于不确定状态。
     */
    public static <T> void setAll(T[] array, IntFunction<? extends T> generator) {
        Objects.requireNonNull(generator);
        for (int i = 0; i < array.length; i++)
            array[i] = generator.apply(i);
    }

    /**
     * 使用提供的生成器函数并行设置指定数组的所有元素,以计算每个元素。
     * 如果生成器函数引发异常,则会从{@code parallelSetAll}引发未经检查的异常,并且数组将处于不确定状态。
     *
     */
    public static <T> void parallelSetAll(T[] array, IntFunction<? extends T> generator) {
        Objects.requireNonNull(generator);
        IntStream.range(0, array.length).parallel().forEach(i -> { array[i] = generator.apply(i); });
    }
    
    /**
     *
     * 省略各种setAll 和 parallelSetAll 方法
     */
    
    

    /**.
     * 返回一个覆盖所有指定数组的{@link Spliterator}。
     */
    public static <T> Spliterator<T> spliterator(T[] array) {
        return Spliterators.spliterator(array,
                                        Spliterator.ORDERED | Spliterator.IMMUTABLE);
    }
    
    /*
     * 省略各种 spliterator方法
     */

    /**
     * 返回以指定数组为源的顺序{@link Stream}。 
     */
    public static <T> Stream<T> stream(T[] array) {
        return stream(array, 0, array.length);
    }

    /**
     * 省略各种stream方法
     */
    
}