源码剖析集合类——Arrays

此博客用于个人学习,来源于书籍和网上,对知识点进行一个整理。

重要的工具类—— Arrays 类:

Java.uti.Arrays 是 JDK 提供的一个工具类,用来处理数组的各种方法,而且每个方法基本上都是静态方法,能直接通过类名 Arrays 调用。

1. asList 方法:

该方法的作用是返回由指定数组支持的固定大小列表。

/**
 * 返回指定数组支持的固定大小列表:要注意到这里的参数是泛型
 *
 * Returns a fixed-size list backed by the specified array.  (Changes to
 * the returned list "write through" to the array.)  This method acts
 * as bridge between array-based and collection-based APIs, in
 * combination with {@link Collection#toArray}.  The returned list is
 * serializable and implements {@link RandomAccess}.
 *
 * <p>This method also provides a convenient way to create a fixed-size
 * list initialized to contain several elements:
 * <pre>
 *     List&lt;String&gt; stooges = Arrays.asList("Larry", "Moe", "Curly");
 * </pre>
 *
 * @param <T> the class of the objects in the array
 * @param a the array by which the list will be backed
 * @return a list view of the specified array
 */
@SafeVarargs
@SuppressWarnings("varargs")
public static <T> List<T> asList(T... a) {
    return new ArrayList<>(a);
}

要注意的是:这个 ArrayList 不是常用的集合类 Java.util.ArrayList,而是 Arrays 的一个内部类。

1)返回的 ArrayList 数组是一个定长列表,只能对其进行查看和修改,但是不能进行添加或者删除操作。如果对其进行增加或者删除操作,都会调用其父类 AbstractList 对应的方法,最终会抛出异常。

2)在 Arrays.asList 源码中,方法声明为 <T> List<T> asList(T…a)。该方法接收一个可变参数,并且这个可变参数类型是作为泛型的参数。基本数据类型是不能作为泛型的参数的,但是数组是引用类型,所以数组是泛型化的,于是 int[] 作为整个参数类型,而不是 int 作为参数类型。

3)返回的列表 ArrayList 里面的元素都是引用,而不是独立出来的对象,这里修改集合的内容,原数组的内容也会发生改变。

ArrayList.asList 比较适合那些已经有数组或者一些元素,而需要快速构建一个 List,只用于读取操作,而不进行添加或者删除操作的场景。

2. sort 方法:

该方法是用于数组排序,在 Arrays 类中有该方法的一系列重载方法,它能对7种基本数据类型,包括 byte、char、double、float、int、long、short 进行排序,后遇 Object 类型(实现了 Comparable 接口)以及比较器 Comparator。

/**
 * 将数组按照升序的顺序排列
 *
 * Sorts the specified array into ascending numerical order.
 *
 * <p>Implementation note: The sorting algorithm is a Dual-Pivot Quicksort
 * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
 * offers O(n log(n)) performance on many data sets that cause other
 * quicksorts to degrade to quadratic performance, and is typically
 * faster than traditional (one-pivot) Quicksort implementations.
 *
 * @param a the array to be sorted
 */
public static void sort(int[] a) {
    DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0);
}

在 Arrays.sort 方法内部调用 DualPivotQuicksort.sort 方法,这个方法的源码很长,分别对于数组的长度进行了各种算法的划分,包括快速排序、插入排序、冒泡排序等。

3. binarySearch 方法:

用 binarySearch 方法查找数组中的某个元素,该方法和 sort 方法一样,适用于各种数组类型以及对象。

/**
 * 查找数组中的某个元素,适用于各种基本数据类型以及对象
 *
 * Searches a range of
 * the specified array of floats for the specified value using
 * the binary search algorithm.
 * The range must be sorted
 * (as by the {@link #sort(float[], int, int)} method)
 * prior to making this call. If
 * it is not sorted, the results are undefined. If the range contains
 * multiple elements with the specified value, there is no guarantee which
 * one will be found. This method considers all NaN values to be
 * equivalent and equal.
 *
 * @param a the array to be searched
 * @param fromIndex the index of the first element (inclusive) to be
 *          searched
 * @param toIndex the index of the last element (exclusive) to be searched
 * @param key the value to be searched for
 * @return index of the search key, if it is contained in the array
 *         within the specified range;
 *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>. The
 *         <i>insertion point</i> is defined as the point at which the
 *         key would be inserted into the array: the index of the first
 *         element in the range greater than the key,
 *         or <tt>toIndex</tt> if all
 *         elements in the range are less than the specified key. Note
 *         that this guarantees that the return value will be &gt;= 0 if
 *         and only if the key is found.
 * @throws IllegalArgumentException
 *         if {@code fromIndex > toIndex}
 * @throws ArrayIndexOutOfBoundsException
 *         if {@code fromIndex < 0 or toIndex > a.length}
 * @since 1.6
 */
public static int binarySearch(float[] a, int fromIndex, int toIndex,
                               float key) {
    rangeCheck(a.length, fromIndex, toIndex);
    return binarySearch0(a, fromIndex, toIndex, key);
}

// Like public version, but without range checks.
private static int binarySearch0(float[] a, int fromIndex, int toIndex,
                                 float key) {
    int low = fromIndex;
    int high = toIndex - 1;

    while (low <= high) {
        int mid = (low + high) >>> 1;//取中间值下标
        float midVal = a[mid];//取中间值

        if (midVal < key)
            low = mid + 1;  // Neither val is NaN, thisVal is smaller
        else if (midVal > key)
            high = mid - 1; // Neither val is NaN, thisVal is larger
        else {
            int midBits = Float.floatToIntBits(midVal);
            int keyBits = Float.floatToIntBits(key);
            if (midBits == keyBits)     // Values are equal
                return mid;             // Key found
            else if (midBits < keyBits) // (-0.0, 0.0) or (!NaN, NaN)
                low = mid + 1;
            else                        // (0.0, -0.0) or (NaN, !NaN)
                high = mid - 1;
        }
    }
    return -(low + 1);  // key not found.
}
4. copyOf 方法:

copyOf 方法用于拷贝数组元素,底层采用 System.arraycopy() 实现,这是一个 native 方法。

/**
 * Copies an array from the specified source array, beginning at the
 * specified position, to the specified position of the destination array.
 * A subsequence of array components are copied from the source
 * array referenced by <code>src</code> to the destination array
 * referenced by <code>dest</code>. The number of components copied is
 * equal to the <code>length</code> argument. The components at
 * positions <code>srcPos</code> through
 * <code>srcPos+length-1</code> in the source array are copied into
 * positions <code>destPos</code> through
 * <code>destPos+length-1</code>, respectively, of the destination
 * array.
 * <p>
 * If the <code>src</code> and <code>dest</code> arguments refer to the
 * same array object, then the copying is performed as if the
 * components at positions <code>srcPos</code> through
 * <code>srcPos+length-1</code> were first copied to a temporary
 * array with <code>length</code> components and then the contents of
 * the temporary array were copied into positions
 * <code>destPos</code> through <code>destPos+length-1</code> of the
 * destination array.
 * <p>
 * If <code>dest</code> is <code>null</code>, then a
 * <code>NullPointerException</code> is thrown.
 * <p>
 * If <code>src</code> is <code>null</code>, then a
 * <code>NullPointerException</code> is thrown and the destination
 * array is not modified.
 * <p>
 * Otherwise, if any of the following is true, an
 * <code>ArrayStoreException</code> is thrown and the destination is
 * not modified:
 * <ul>
 * <li>The <code>src</code> argument refers to an object that is not an
 *     array.
 * <li>The <code>dest</code> argument refers to an object that is not an
 *     array.
 * <li>The <code>src</code> argument and <code>dest</code> argument refer
 *     to arrays whose component types are different primitive types.
 * <li>The <code>src</code> argument refers to an array with a primitive
 *    component type and the <code>dest</code> argument refers to an array
 *     with a reference component type.
 * <li>The <code>src</code> argument refers to an array with a reference
 *    component type and the <code>dest</code> argument refers to an array
 *     with a primitive component type.
 * </ul>
 * <p>
 * Otherwise, if any of the following is true, an
 * <code>IndexOutOfBoundsException</code> is
 * thrown and the destination is not modified:
 * <ul>
 * <li>The <code>srcPos</code> argument is negative.
 * <li>The <code>destPos</code> argument is negative.
 * <li>The <code>length</code> argument is negative.
 * <li><code>srcPos+length</code> is greater than
 *     <code>src.length</code>, the length of the source array.
 * <li><code>destPos+length</code> is greater than
 *     <code>dest.length</code>, the length of the destination array.
 * </ul>
 * <p>
 * Otherwise, if any actual component of the source array from
 * position <code>srcPos</code> through
 * <code>srcPos+length-1</code> cannot be converted to the component
 * type of the destination array by assignment conversion, an
 * <code>ArrayStoreException</code> is thrown. In this case, let
 * <b><i>k</i></b> be the smallest nonnegative integer less than
 * length such that <code>src[srcPos+</code><i>k</i><code>]</code>
 * cannot be converted to the component type of the destination
 * array; when the exception is thrown, source array components from
 * positions <code>srcPos</code> through
 * <code>srcPos+</code><i>k</i><code>-1</code>
 * will already have been copied to destination array positions
 * <code>destPos</code> through
 * <code>destPos+</code><i>k</I><code>-1</code> and no other
 * positions of the destination array will have been modified.
 * (Because of the restrictions already itemized, this
 * paragraph effectively applies only to the situation where both
 * arrays have component types that are reference types.)
 *
 * @param      src      the source array.
 * @param      srcPos   starting position in the source array.
 * @param      dest     the destination array.
 * @param      destPos  starting position in the destination data.
 * @param      length   the number of array elements to be copied.
 * @exception  IndexOutOfBoundsException  if copying would cause
 *               access of data outside array bounds.
 * @exception  ArrayStoreException  if an element in the <code>src</code>
 *               array could not be stored into the <code>dest</code> array
 *               because of a type mismatch.
 * @exception  NullPointerException if either <code>src</code> or
 *               <code>dest</code> is <code>null</code>.
 */
public static native void arraycopy(Object src,  int  srcPos,
                                    Object dest, int destPos,
                                    int length);
  • src:源数组
  • srcPos:源数组要复制的起始位置
  • dest:目的数组
  • destPos:目的数组放置的起始位置
  • length:复制的长度

src 和 dest 都必须是同类型或者可以进行转换类型的数组。

5. equals 和 deepEquals 方法:

equals 用来比较两个数组中对应位置的每个元素是否相等。

先看 int 类型的数组比较,源码如下:

/**
 * Returns <tt>true</tt> if the two specified arrays of ints are
 * <i>equal</i> to one another.  Two arrays are considered equal if both
 * arrays contain the same number of elements, and all corresponding pairs
 * of elements in the two arrays are equal.  In other words, two arrays
 * are equal if they contain the same elements in the same order.  Also,
 * two array references are considered equal if both are <tt>null</tt>.<p>
 *
 * @param a one array to be tested for equality
 * @param a2 the other array to be tested for equality
 * @return <tt>true</tt> if the two arrays are equal
 */
public static boolean equals(int[] a, int[] a2) {
    //数组引用相等,则里面的元素一定相等
    if (a==a2)
        return true;
    //两个数组其中一个为 null,返回 false
    if (a==null || a2==null)
        return false;

    int length = a.length;
    //两个数组长度不等,返回 false
    if (a2.length != length)
        return false;

    //通过 for 循环依次比较每个元素是否相等
    for (int i=0; i<length; i++)
        if (a[i] != a2[i])
            return false;

    return true;
}

再看对象数组的比较:

/**
 * Returns <tt>true</tt> if the two specified arrays of Objects are
 * <i>equal</i> to one another.  The two arrays are considered equal if
 * both arrays contain the same number of elements, and all corresponding
 * pairs of elements in the two arrays are equal.  Two objects <tt>e1</tt>
 * and <tt>e2</tt> are considered <i>equal</i> if <tt>(e1==null ? e2==null
 * : e1.equals(e2))</tt>.  In other words, the two arrays are equal if
 * they contain the same elements in the same order.  Also, two array
 * references are considered equal if both are <tt>null</tt>.<p>
 *
 * @param a one array to be tested for equality
 * @param a2 the other array to be tested for equality
 * @return <tt>true</tt> if the two arrays are equal
 */
public static boolean equals(Object[] a, Object[] 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++) {
        Object o1 = a[i];
        Object o2 = a2[i];
        if (!(o1==null ? o2==null : o1.equals(o2)))
            return false;
    }

    return true;
}

deepEquals 也是用来比较两个数组的元素是否相等,不过 deepEquals 能够比较多维数组,而且是任意层次的嵌套数组。

6. fill 方法:

该方法用于给数组赋值,并能指定某个赋值范围。

/**
 * 给a数组所有元素赋值val
 *
 * Assigns the specified int value to each element of the specified array
 * of ints.
 *
 * @param a the array to be filled
 * @param val the value to be stored in all elements of the array
 */
public static void fill(int[] a, int val) {
    for (int i = 0, len = a.length; i < len; i++)
        a[i] = val;
}

/**
 * 给从fromIndex开始的下标,toIndex-1结尾的下标都赋值val,左闭右开
 *
 * Assigns the specified int value to each element of the specified
 * range of the specified array of ints.  The range to be filled
 * extends from index <tt>fromIndex</tt>, inclusive, to index
 * <tt>toIndex</tt>, exclusive.  (If <tt>fromIndex==toIndex</tt>, the
 * range to be filled is empty.)
 *
 * @param a the array to be filled
 * @param fromIndex the index of the first element (inclusive) to be
 *        filled with the specified value
 * @param toIndex the index of the last element (exclusive) to be
 *        filled with the specified value
 * @param val the value to be stored in all elements of the array
 * @throws IllegalArgumentException if <tt>fromIndex &gt; toIndex</tt>
 * @throws ArrayIndexOutOfBoundsException if <tt>fromIndex &lt; 0</tt> or
 *         <tt>toIndex &gt; a.length</tt>
 */
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;
}
7. toString 和 deepToString 方法:

toString 用来打印一位数组的元素,而 deepToString 用来打印多层嵌套的数组元素。

/**
 * 打印一维数组的元素
 *
 * Returns a string representation of the contents of the specified array.
 * The string representation consists of a list of the array's elements,
 * enclosed in square brackets (<tt>"[]"</tt>).  Adjacent elements are
 * separated by the characters <tt>", "</tt> (a comma followed by a
 * space).  Elements are converted to strings as by
 * <tt>String.valueOf(int)</tt>.  Returns <tt>"null"</tt> if <tt>a</tt> is
 * <tt>null</tt>.
 *
 * @param a the array whose string representation to return
 * @return a string representation of <tt>a</tt>
 * @since 1.5
 */
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(", ");
    }
}

/**
 * 用来打印多层嵌套的数组元素
 *
 * Returns a string representation of the "deep contents" of the specified
 * array.  If the array contains other arrays as elements, the string
 * representation contains their contents and so on.  This method is
 * designed for converting multidimensional arrays to strings.
 *
 * <p>The string representation consists of a list of the array's
 * elements, enclosed in square brackets (<tt>"[]"</tt>).  Adjacent
 * elements are separated by the characters <tt>", "</tt> (a comma
 * followed by a space).  Elements are converted to strings as by
 * <tt>String.valueOf(Object)</tt>, unless they are themselves
 * arrays.
 *
 * <p>If an element <tt>e</tt> is an array of a primitive type, it is
 * converted to a string as by invoking the appropriate overloading of
 * <tt>Arrays.toString(e)</tt>.  If an element <tt>e</tt> is an array of a
 * reference type, it is converted to a string as by invoking
 * this method recursively.
 *
 * <p>To avoid infinite recursion, if the specified array contains itself
 * as an element, or contains an indirect reference to itself through one
 * or more levels of arrays, the self-reference is converted to the string
 * <tt>"[...]"</tt>.  For example, an array containing only a reference
 * to itself would be rendered as <tt>"[[...]]"</tt>.
 *
 * <p>This method returns <tt>"null"</tt> if the specified array
 * is <tt>null</tt>.
 *
 * @param a the array whose string representation to return
 * @return a string representation of <tt>a</tt>
 * @see #toString(Object[])
 * @since 1.5
 */
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();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值