Arrays
此類包含數組操作的各種方法(比如排序和搜索)。此類還包含一個允許將數組作爲列表來查看的靜態工廠。除非特別註明,否則如果指定數組引用爲null,則此類中的方法都會拋出 NullPointerException
Arrays的主要方法:sort(),binarySearch(),equals(),copyOf(),toString()等。
sort
我們先看看排序方法sort(),這裏的排序會根據不同的排序對象而採取不同的排序方式,主要是快速排序(Dual-Pivot Quicksort)。到了JDK1.7專門把排序功能封裝成一個類:DualPivotQuicksort
下面我們看看byte數組的排序sort(byte[]),這個比較簡單,使用了計數排序(CountSort)和插入排序(InsertSort)。
【int[]的排序使用了快速排序(Quicksort)和歸併排序(mergeSort),臨界爲286,大的用後者】
(具體不同排序的實現,待續,此處不做討論。)
public static void sort(byte[] a) {
DualPivotQuicksort.sort(a);
}
public static void sort(byte[] a, int left, int right) {
// Use counting sort on large arrays
if (right - left > COUNTING_SORT_THRESHOLD_FOR_BYTE) {
int[] count = newint[NUM_BYTE_VALUES];
for (int i = left - 1; ++i <= right;
count[a[i] - Byte.MIN_VALUE]++
);
for (int i = NUM_BYTE_VALUES, k = right + 1; k> left; ) {
while (count[--i] == 0);
byte value = (byte) (i + Byte.MIN_VALUE);
int s = count[i];
do {
a[--k] = value;
} while (--s > 0);
}
} else { // Use insertion sort on small arrays
for (int i = left, j = i; i < right; j = ++i) {
byte ai = a[i + 1];
while (ai < a[j]) {
a[j + 1] = a[j];
if (j-- == left)
break;
}
a[j + 1] = ai;
}
}
}
這裏有幾個地方是比較有意思的,比如說第一個計數排序中,使用k來處理相同元素的連續存放。
還有,簡化了一個循環統計的寫法,讓我們看得很彆扭,如下:
for (int i = left - 1; ++i <= right;
count[a[i] - Byte.MIN_VALUE]++
);
替換成下面形式,更容易理解:
for (int i = 0; i < arrObj.length; i++)
count[arrObj[i] - Byte.MIN_VALUE]++;
由上可知,由於byte中k的範圍是256,所以時間複雜度爲O(n+256)。因此當n少的時候用插入排序更快,臨界爲29。
/** If the length of a byte array to be sorted is greaterthan this constant, counting sort isused in preference to insertion sort. */
private static final int COUNTING_SORT_THRESHOLD_FOR_BYTE = 29;
binarySearch
二分法查找通過binarySearch()實現,但是前提是,原數組要是有序的,否則二分查找就沒有意義了。
public static int binarySearch(int[] a, int 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;
elseif (midVal > key)
high = mid - 1;
else
return mid; // keyfound
}
return -(low + 1); // key not found.
}
equals
判斷數組相等的標準是:次序和元素的完全相等。和String相等是一個標準,就是遍歷下標,相同下標的元素都相等,數組才相等。
public static boolean equals(int[] a, int[] a2) {
if (a==a2) returntrue;
if (a==null || a2==null) returnfalse;
int length = a.length;
if (a2.length != length) returnfalse;
for (int i=0; i<length; i++)
if (a[i] != a2[i])
returnfalse;
returntrue;
}
copyOf
複製數組copyOf(T[], int),從T[]複製int長度的數組元素,返回類型爲T[]。這裏使用了泛型,而複製工作由System.arraycopy()來完成。
這裏的邏輯:先創建一個指定長度newLength的數組,填充null (數組初始化自動完成),然後從original複製指定長度Math.min(original.length, newLength),從0開始。
publicstatic <T> T[] copyOf(T[]original, int newLength) {
return (T[]) copyOf(original,newLength, original.getClass());
}
publicstatic <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;
}
toString
對於數組本身來說,toString只是繼承Object.toString(),所以只會返回一個地址串,這樣不便於觀察數組。
所以我們可以通過Arrays.toString()來打印數組的詳情:遍歷每個數組元素,逐個toString()拼裝成 [2,5,3,6]的形式。
另外,對於二維數組,可以使用deepToString()來進行深層次的toString。
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(", ");
}
}
other
填充數組,from到to填充成val
publicstaticvoid fill(int[] a, int fromIndex, int toIndex, int val) {
rangeCheck(a.length, fromIndex,toIndex); // 檢查數組範圍
for (int i = fromIndex; i < toIndex; i++)
a[i] = val;
}
hashCode的Time33算法,具體見HashMap.hashCode()或《Effective
Java》,String中也是同樣的實現,不過因爲可變性,這裏沒有像String那樣緩存起來。
public static int hashCode(int a[]) {
if (a == null)
return 0;
int result = 1;
for (int element : a)
result = 31 * result + element;
return result;
}
asList方法是用了可變參數和泛型,只要輸入的T,則返回ArrayList<T>的列表。
此處還使用註解【SafeVarargs】,說明可變長參數的方法在與泛型類一起使用時不會出現類型安全問題。
@SafeVarargs
publicstatic <T> List<T> asList(T... a) {
returnnewArrayList<>(a);
}
這裏的可變參數,讓使用變得很靈活,下面兩種形式都是可以的。
Integer[] arrSrc = {3,2,1};
List<Integer> list1 = Arrays.asList(arrSrc);
List<Integer> list2 = Arrays.asList(3,2,1);
--源碼取自JDK1.7