Arrays.java是Java中用來操作數(shù)組的類。使用這個(gè)工具類可以減少平常很多的工作量。了解其實(shí)現(xiàn),可以避免一些錯(cuò)誤的用法。 它提供的操作包括: 排序 sort 查找 binarySearch() 比較 equals 填充 fill 轉(zhuǎn)列表 asList() 哈希 Hash() 轉(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
|