JDK1.7-Arrays源码详解

 

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]++;

 

由上可知,由于bytek的范围是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

填充数组,fromto填充成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;

}


hashCodeTime33算法,具体见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

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值