Java 源碼--Arrays

前言

數組比較特殊,一個數組屬於一個對象,但是它的創建方式卻不同於一般對象。

Java中的數組創建數組有以下三種方式:

// 第一種
int[] array = new int[5];
// 第二種
int[] array = {1, 2, 3, 4, 5};
// 第三種
int[] array = new int[]{1, 2, 3, 4, 5};

判斷數組是否屬於一個對象可使用下列語句:

System.out.println(new int[2] instanceof Object);

源碼分析

接下來我們就來看一下對數據進行操作的工具類Arrays。

Arrays源代碼看似很多,其實核心方法只有幾個,Arrays給每種數據類型都提供了方法。

sort()

sort()方法有兩種實現。第一種使用雙軸快速排序算法。

public static void sort(int[] a, int fromIndex, int toIndex) {
    rangeCheck(a.length, fromIndex, toIndex);
    DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0);
}

第二種根據系統屬性設置使用舊的歸併排序算法或者帶比較的分區排序算法。

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

parallelSort()

parallelSort()是Java8新增的並行排序算法,基於fork/join框架。PS:Fork/Join框架是Java7提供的一個用於並行執行任務的框架,是一個把大任務分割成若干個小任務,最終彙總每個小任務結果後得到大任務結果的框架。

public static void parallelSort(int[] a, int fromIndex, int toIndex) {
    rangeCheck(a.length, fromIndex, toIndex);
    int n = toIndex - fromIndex, p, g;
    if (n <= MIN_ARRAY_SORT_GRAN ||
        (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
        DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0);
    else
        new ArraysParallelSortHelpers.FJInt.Sorter
        (null, a, new int[n], fromIndex, n, 0,
         ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
         MIN_ARRAY_SORT_GRAN : g).invoke();
}

ArraysParallelSortHelpers類中源碼有些複雜,就先不探究它了。我們來比較一下sort()和parallelSort()的性能。從數組長度10開始,到長度100000000,打印倆個鬧鐘功能排序消耗的時間。

public static void main(String[] args) {
    for (int i = 10; i <= 100000000; i *= 10) {
        test(i);
    }
}

static void test(int limit) {
    IntStream intStream = new Random().ints(limit);
    int[] arr1 = intStream.toArray();
    int[] arr2 = Arrays.copyOf(arr1, arr1.length);

    long t1 = System.currentTimeMillis();
    Arrays.sort(arr1);
    long t2 = System.currentTimeMillis();
    Arrays.parallelSort(arr2);
    long t3 = System.currentTimeMillis();
    System.out.println("數組長度:" + limit + "\tsort:" + (t2 - t1) + "ms\tparallelSort:" + (t3 - t2) + "ms");
}

輸出結果:

數組長度:10	sort:1ms	parallelSort:0ms
數組長度:100	sort:0ms	parallelSort:0ms
數組長度:1000	sort:0ms	parallelSort:1ms
數組長度:10000	sort:3ms	parallelSort:10ms
數組長度:100000	sort:16ms	parallelSort:22ms
數組長度:1000000	sort:105ms	parallelSort:48ms
數組長度:10000000	sort:1235ms	parallelSort:412ms
數組長度:100000000	sort:10194ms	parallelSort:4820ms

可以看出,從長度1000000開始,並行排序消耗的時間比串行排序消耗的時間變短。所以,在一般情況下,使用sort()方法即可,當數組長度很大時,使用parallelSort()方法。

parallelPrefix()

串行計算數組累加值。

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

binarySearch()

二分查找。使用的前提是數組是已經從小到大排好序的。

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

private static int binarySearch0(long[] a, int fromIndex, int toIndex,
                                 long key) {
    int low = fromIndex;
    int high = toIndex - 1;

    while (low <= high) {
        int mid = (low + high) >>> 1;
        long 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.
}

equals()

判斷兩個數組是否相等,包括基本類型、對象的判等。基本類型的判等就是先判斷結構上是否相等,然後調用ArraysSupport類的mismatch()方法判斷內容的相等性。

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;

    return ArraysSupport.mismatch(a, a2, length) < 0;
}

fill()

填充。

public static void fill(long[] a, long val) {
    for (int i = 0, len = a.length; i < len; i++)
        a[i] = val;
}

copyOf()和copyOfRange()

複製和複製指定範圍。

public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
    @SuppressWarnings("unchecked")
    T[] copy = ((Object)newType == (Object)Object[].class)
        ? (T[]) new Object[newLength]
        : (T[]) Array.newInstance(newType.getComponentType(), newLength);
    System.arraycopy(original, 0, copy, 0,
                     Math.min(original.length, newLength));
    return copy;
}

public static <T,U> T[] copyOfRange(U[] original, int from, int to, Class<? extends T[]> newType) {
    int newLength = to - from;
    if (newLength < 0)
        throw new IllegalArgumentException(from + " > " + to);
    @SuppressWarnings("unchecked")
    T[] copy = ((Object)newType == (Object)Object[].class)
        ? (T[]) new Object[newLength]
        : (T[]) Array.newInstance(newType.getComponentType(), newLength);
    System.arraycopy(original, from, copy, 0,
                     Math.min(original.length - from, newLength));
    return copy;
}

asList()

返回List。這裏返回的ArrayList是Arrays中的一個靜態內部類。

public static <T> List<T> asList(T... a) {
    return new ArrayList<>(a);
}

hashCode()

返回哈希值。

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

toString()

返回字符串。

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(", ");
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章