日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

讀 Java Arrays 源碼 筆記

 昵稱73595512 2021-02-18

Arrays.java是Java中用來操作數(shù)組的類。使用這個(gè)工具類可以減少平常很多的工作量。了解其實(shí)現(xiàn),可以避免一些錯(cuò)誤的用法。

它提供的操作包括:

  1. 排序 sort

  2. 查找 binarySearch()

  3. 比較 equals

  4. 填充 fill

  5. 轉(zhuǎn)列表 asList()

  6. 哈希 Hash()

  7. 轉(zhuǎn)字符串 toString()

這個(gè)類的代碼量很多,Java1.7中有4000多行。因?yàn)槊恳环N基本類型都做了兼容,所以整個(gè)類真正邏輯不多。下面簡單介紹一下它各個(gè)功能的實(shí)現(xiàn):

排序

這里的排序?qū)崿F(xiàn)有兩種

一種是為基本類型數(shù)組設(shè)計(jì)的,它的對(duì)外接口有兩種,如下:

//whole array
public static void sort(primitive[] a);

//sub array
public static void sort(primitive[] a, int fromIndex, int toIndex);

它們的具體實(shí)現(xiàn)方式是一樣的都是調(diào)用了DualPivotQuicksort.sort(...)方法。這個(gè)方法的中文含義是 雙軸快速排序。它在性能上優(yōu)于傳統(tǒng)的單軸快速排序。

算法的邏輯可以參考
如果想要閱讀源碼可以參考我的另一篇博客

它是不穩(wěn)定的

另一種是為Object對(duì)象設(shè)計(jì)的,它要求傳進(jìn)來的數(shù)組對(duì)象必須實(shí)現(xiàn)Comparable接口。
它提供的接口如下:

// whole array, default asec
public static void sort(Object[] a);

// subArray, default asec
public static void sort(Object[] a, int fromIndex, int toIndex);

還有帶泛型參數(shù)的接口,它需要指定一個(gè)比較器。

// whole array with comparator
public static <T> void sort(T[] a, Comparator<? super T> c);

// sub array with comparator
public static <T> void sort(T[] a, int fromIndex, int toIndex, Comparator<? super T> c);

他的實(shí)現(xiàn)方式如下:

// java/utils/Arrays.java
static final class LegacyMergeSort {
    private static final boolean userRequested =
        java.security.AccessController.doPrivileged(
            new sun.security.action.GetBooleanAction(
                "java.util.Arrays.useLegacyMergeSort")).booleanValue();
}

//sort 方法的實(shí)現(xiàn)
public static void sort(Object[] a) {
if (LegacyMergeSort.userRequested)
   legacyMergeSort(a);
else
   //與TimSort的邏輯是相同的
   ComparableTimSort.sort(a);
}

//legacyMergeSort
private static void legacyMergeSort(Object[] a) {
Object[] aux = a.clone();
mergeSort(aux, a, 0, a.length, 0);
}                     

//歸并排序
private static void mergeSort(Object[] src,
                              Object[] dest,
                              int low,
                              int high,
                              int off) {
    // 小數(shù)組直接進(jìn)行普通插入排序
    if (length < INSERTIONSORT_THRESHOLD) {
         ///...
        return;
    }

    //下面是歸并排序的實(shí)現(xiàn),
    ///...
}

從上面的邏輯可以看出來,它的實(shí)現(xiàn)方式分為兩種,一種是通過Arrays.java中的歸并排序?qū)崿F(xiàn)的,另一種采用了TimSort算法。其中Arrays.java中的歸并排序的邏輯相對(duì)簡單,是一種插入排序與傳統(tǒng)歸并排序的結(jié)合。當(dāng)待排序的數(shù)組小于INSERTIONSROT_THERSHOLD的時(shí)候直接進(jìn)行插入排序,不再遞歸。TimSort算法也是一種插入排序與歸并排序結(jié)合的算法,不過它的細(xì)節(jié)優(yōu)化要比Arrays.java中的算法做的多。詳細(xì)介紹可以參考或者我的。

兩種算法的切換依靠運(yùn)行時(shí)系統(tǒng)變量的設(shè)置。具體參考上的一篇回答。我們默認(rèn)情況下是不打開這個(gè)開關(guān)的,也就是說沒有特殊要求的情況下,我們默認(rèn)使用TimSort算法來實(shí)現(xiàn)排序。從注釋上來看,在未來某個(gè)版本,Arrays.java中的merge方法將會(huì)被刪除掉。

這個(gè)排序方法是穩(wěn)定的。

查找

Arrays.java中只提供了二分查找。二分查找的前提就是數(shù)組是經(jīng)過升序排序的,所以使用之前務(wù)必確保數(shù)組是有序的。

調(diào)用的接口比較簡單:

public static int binarySearch(primative[] a, primative key);
public static int binarySearch(primative[] a, int fromIndex, int toIndex, primative 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);


equals

這個(gè)也比較簡單,equals方法與==的不同大家應(yīng)該都很熟悉了,這里直接貼出接口:

// 基本類型
public static boolean equals(long[] a, long[] a2) {
    //...
}
// 對(duì)象
public static boolean equals(Object[] a, Object[] a2) {
    //...
}
// 高維數(shù)組的equal比較,通過遞歸實(shí)現(xiàn)
// 這里沒有對(duì)循環(huán)引用進(jìn)行檢查,如果兩個(gè)如組同時(shí)存在循環(huán)引用的情況下可能出現(xiàn)死循環(huán)的風(fēng)險(xiǎn)。
public static boolean deepEquals(Object[] a1, Object[] a2) {
   //...
}

fill 填充

批量初始化的時(shí)候不要自己寫for循環(huán)了,已經(jīng)有人幫我們寫好了。

// 基本類型批量賦值
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;
}
// 對(duì)象批量賦值
public static void fill(Object[] a, int fromIndex, int toIndex, Object val) {
    rangeCheck(a.length, fromIndex, toIndex);
    for (int i = fromIndex; i < toIndex; i++)
        a[i] = val;
}


復(fù)制

數(shù)組復(fù)制的最終實(shí)現(xiàn)是調(diào)用了JVM中的方法。具體沒有深究,但在數(shù)據(jù)量大的時(shí)候應(yīng)該能快些。

// @file Arrays.java
// 基本類型的復(fù)制,從0開始到指定長度
public static byte[] copyOf(byte[] original, int newLength) {
    byte[] copy = new byte[newLength];
    System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength));
    return copy;
}
// 基本類型復(fù)制,從指定起點(diǎn)到指定終點(diǎn)
public static byte[] copyOfRange(byte[] original, int from, int to) {
    int newLength = to - from;
    if (newLength < 0)
        throw new IllegalArgumentException(from + " > " + to);
    byte[] copy = new byte[newLength];
    System.arraycopy(original, from, copy, 0,
                    Math.min(original.length - from, newLength));
    return copy;
}
//這里是泛型數(shù)組的復(fù)制, 結(jié)合泛型進(jìn)階中的內(nèi)容,這里好理解很多。
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
    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;
}

// @file System.java
public static native void arraycopy(Object src,  int  srcPos, Object dest, int destPos, int length);

//


轉(zhuǎn)換成列表 asList

將一組對(duì)象轉(zhuǎn)換成列表,這里一定要注意返回的ArrayList并非平常用的java.util.ArrayList ,而是Arrays.java中定義的一個(gè)簡單的靜態(tài)內(nèi)部類--ArrayList。它不支持添加和移除元素,不支持?jǐn)U容。

@file java/util/Arrays.java

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

//注意,此ArrayList非平常用的ArrayList;這里的實(shí)現(xiàn)比較簡單。
//不能擴(kuò)容,所以不支持add,remove等操作。
private static class ArrayList<E> extends AbstractList<E>
    implements RandomAccess, java.io.Serializable {
    /// ...
}


哈希 hash

高維數(shù)組的哈希計(jì)算,采用遞歸實(shí)現(xiàn)。同樣,如果自己的某個(gè)元素直接或者間接持有自己,會(huì)出現(xiàn)死循環(huán)。

// 基本類型哈希
public static int hashCode(long a[]) {
   // ...
}

// 對(duì)象哈希
public static int hashCode(Object a[]) {
   //...
}

// 高維數(shù)組哈希,采用遞歸實(shí)現(xiàn)。如果自己的某個(gè)元素直接或者間接持有自己,會(huì)出現(xiàn)死訊環(huán),
// 所以`Object[]`最好直接使用`hashcode(Object)`。
public static int deepHashCode(Object a[]) {
   //...
}

toString

有了這個(gè)方法,打Log的時(shí)候就不需要寫循環(huán)了。
這里的高維數(shù)組直接或者間接持有自己的情況不會(huì)出現(xiàn)死循環(huán)。因?yàn)檫@里做了特殊處理,用一個(gè)Set保存了打印過的數(shù)組。

// 基本類型
public static String toString(int[] a) {
   // ...
}
// 對(duì)象
public static String toString(Object[] a) {
    // ...
}
// 高維數(shù)組toString(). 這里處理了自我持有的問題。
public static String deepToString(Object[] a) {
    // ...
    deepToString(a, buf, new HashSet<Object[]>());
    return buf.toString();
}
// 真正的實(shí)現(xiàn)方法, 遞歸實(shí)現(xiàn)。
// 使用了一個(gè)Set來存儲(chǔ)已經(jīng)打印過的類,如果再次出現(xiàn)這個(gè)對(duì)象,直接打印[...]
private static void deepToString(Object[] a, StringBuilder buf,
                                 Set<Object[]> dejaVu) {
   //...
}

文章來源:https://www./blog-eA5LgU30OF.htm

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多