1. 程式人生 > >jdk原始碼閱讀之Arrays

jdk原始碼閱讀之Arrays

Arrays實現了陣列常見的一些操作,比如:排序、陣列拷貝等。

  • 排序sort

Arrays類為了通用性,對方法進行了大量的過載,在這裡只講通用的。

public static void sort(Object[] a) {
        if (LegacyMergeSort.userRequested)
            legacyMergeSort(a);
        else
            ComparableTimSort.sort(a, 0, a.length, null, 0, 0);
    }

進行排序的陣列一定要實現Comparable介面,否則會報錯,舉個例子:

import java.util.Arrays;
class A  implements Comparable<A>  {
	private int i;
	public A(int i) {
		this.i = i;
	}
@Override
public int compareTo(A o) {
		int oi = o.i;
		return i > oi ? 1 : (i == oi ? 0 : -1);
	}
	public int getI() {
		return i;
	}
}
public class TestDemo1 implements Cloneable {
	public static void main(String[] args) throws Exception {
		A[] a = { new A(3), new A(8), new A(4), new A(6), new A(1), };
		Arrays.sort(a);
		for (A a2 : a) {
			System.out.print(a2.getI());
		}
	}
}

這樣陣列a可以正常排序,如果A類沒有實現Comparable介面,在進行排序的時候會報 java.lang.ClassCastException異常。

  • 二分查詢binarySearch

public static int binarySearch(Object[] a, Object key) {
        return binarySearch0(a, 0, a.length, key);
    }
 private static int binarySearch0(Object[] a, int fromIndex, int toIndex,
                                     Object key) {
        int low = fromIndex;
        int high = toIndex - 1;

        while (low <= high) {
            int mid = (low + high) >>> 1;
            @SuppressWarnings("rawtypes")
            Comparable midVal = (Comparable)a[mid];
            @SuppressWarnings("unchecked")
            int cmp = midVal.compareTo(key);

            if (cmp < 0)
                low = mid + 1;
            else if (cmp > 0)
                high = mid - 1;
            else
                return mid; // key found
        }
        return -(low + 1);  // key not found.
    }

由程式碼可知,查詢到的依據是兩者的compareTo方法返回的是否是0,而不是呼叫equals方法,這一點要注意。

  • 陣列相等equals

public static boolean equals(Object[] a, Object[] a2) {
        if (a==a2)
            return true;
        if (a==null || a2==null)
            return false;

        int length = a.length;
        if (a2.length != length)
            return false;

        for (int i=0; i<length; i++) {
            Object o1 = a[i];
            Object o2 = a2[i];
            if (!(o1==null ? o2==null : o1.equals(o2)))
                return false;
        }

        return true;
    }

對比兩個陣列的每一個物件呼叫equals方法,如果每個物件呼叫equals都返回0,那麼說明兩個陣列相等。

  • 填充陣列fill

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

fill方法用來將陣列a的每一個元素都賦值為val,當val是引用的話,那麼陣列的每一個元素都是引用,並且引用的是同一個物件;當val為基本資料型別的話,陣列的每一個元素的值為val。

  • 陣列拷貝copyOf/copyOfRange

@SuppressWarnings("unchecked")
    public static <T> T[] copyOf(T[] original, int newLength) {
        return (T[]) copyOf(original, newLength, original.getClass());
    }
@SuppressWarnings("unchecked")
    public static <T> T[] copyOfRange(T[] original, int from, int to) {
        return copyOfRange(original, from, to, (Class<? extends T[]>) original.getClass());
    }

對於copyOf(T[] original, int newLength),當newLength大於origin陣列的長度時,返回的陣列大小為newLength,剩餘的部分用0填充。
對於copyOfRange(T[] original, int from, int to),是部分拷貝。

  • 將引數轉換成List

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

asList方法是一個帶不定引數的方法,把這些引數轉換成List。