天天看點

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

感興趣的同學可以自己去看看。