elvalad

修仙
Arrays类的分析及使用

1.  Arrays类介绍

Arrays类是Java API中提供的类,在java.util包中,此类包含用来操作数组的各种方法,比如排序和搜索,在这个类中如果指定数组引用为null,则此类方法都会抛出NullPointerException,此类还包含一个允许将数组作为列表来查看的静态工厂。

Arrays类包含sort,binarySearch,equals,fill,copyOf,asList,hashCode,deepHashCode,deepEquals,toString和deepToString public方法供其他类使用。其中从java.lang.Object继承的方法有clone,equals,finalize,getClass hashCode,notify,notifyAll,toString,wait。sort方法用来排序,binarySearch方法是二分查找,equals方法是用来比较,fill方法用来将某个特定的值填充到数组中,copyOf复制特定长度的数组,asList方法的作用是将数组作为列表来查看。

Arrays类包含两个私有类,分别是LegacyMergeSort类和ArrayList类,gacMergeSort是老版本的归并排序实现,而ArrayList是一个数组队列,用于实现asList方法。

Arrays的构造函数

private Arrays() {}

可以看到Arrays的构造函数被被设置为private的,表明这个类禁止使用默认构造函数并且不能被实例化,但是可以通过提供静态方法来使用这个类,这种模式就是单例模式。

Arrays方法摘要

public static void sort(Object[] a)
public static void sort(Object[] a, int fromIndex, int toIndex)
public static <T> void sort(T[] a, Comparator<? super T> c)
public static <T> void sort(T[] a, int fromIndex, int toIndex, Comparator<? super T> c)

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)

public static boolean equals(Object[] a, Object[] a2)

public static void fill(Object[] a, Object val)
public static void fill(Object[] a, int fromIndex, int toIndex, Object val)
public static <T> T[] copyOf(T[] original, int newLength)
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType)

public static <T> T[] copyOfRange(T[] original, int from, int to)
public static <T,U> T[] copyOfRange(U[] original, int from, int to, Class<? extends T[]> newType)

public static <T> List<T> asList(T... a)

public static int hashCode(Object a[])

public static int deepHashCode(Object a[])

public static boolean deepEquals(Object[] a1, Object[] a2)

public static String toString(Object[] a)

public static String deepToString(Object[] a)

2.  Arrays类源码分析

依据JDK1.7.0_45的源码对Arrays类中的主要方法进行分析。

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

此方法表示根据元素的自然顺序对指定对象数组按升序进行排序,当用户没有请求使用老版本的归并排序时,直接使用ComparableTimSort类的方法实现,关于ComparableTimSort类之后会单独进行分析。

public static void sort(Object[] a, int fromIndex, int toIndex) {
        if (LegacyMergeSort.userRequested)
            legacyMergeSort(a, fromIndex, toIndex);
        else
            ComparableTimSort.sort(a, fromIndex, toIndex);
    }

此方法表示的是根据元素的自然顺序对指定对象数组的指定范围按升序进行排序,其他实现与上面的额排序方法相同。

public static <T> void sort(T[] a, Comparator<? super T> c) {
        if (LegacyMergeSort.userRequested)
            legacyMergeSort(a, c);
        else
            TimSort.sort(a, c);
    }

此方法表示根据指定比较器产生的顺序对指定对象数组进行排序。具体的排序实现是调用了TimSort的sort方法实现。

public static <T> void sort(T[] a, int fromIndex, int toIndex,
                                Comparator<? super T> c) {
        if (LegacyMergeSort.userRequested)
            legacyMergeSort(a, fromIndex, toIndex, c);
        else
            TimSort.sort(a, fromIndex, toIndex, c);
    }

此方法表示根据指定比较器产生的顺序对指定对象数组的指定范围进行排序。同上具体的排序实现是调用了TimSort的sort方法实现。TimSort类在之后会单独分析。

 

public static int binarySearch(Object[] a, Object key) {
        return binarySearch0(a, 0, a.length, key);
}

// Like public version, but without range checks.
    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;
            Comparable midVal = (Comparable)a[mid];
            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.
    }

此方法表示使用二分搜索法来搜索指定数组,以获得指定对象,二分查找的具体实现没有进行范围检查。

public static int binarySearch(Object[] a, int fromIndex, int toIndex,
                                   Object key) {
        rangeCheck(a.length, fromIndex, toIndex);
        return binarySearch0(a, fromIndex, toIndex, key);
}

此方法表示使用二分搜索法来搜索指定数组的范围,以获得指定对象。

public static <T> int binarySearch(T[] a, T key, Comparator<? super T> c) {
        return binarySearch0(a, 0, a.length, key, c);
}

// Like public version, but without range checks.
    private static <T> int binarySearch0(T[] a, int fromIndex, int toIndex,
                                         T key, Comparator<? super T> c) {
        if (c == null) {
            return binarySearch0(a, fromIndex, toIndex, key);
        }
        int low = fromIndex;
        int high = toIndex - 1;

        while (low <= high) {
            int mid = (low + high) >>> 1;
            T midVal = a[mid];
            int cmp = c.compare(midVal, 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.
    }

二分查找的的泛型实现,使用二分搜索法来搜索指定数组,以获得指定对象。

public static <T> int binarySearch(T[] a, int fromIndex, int toIndex,
                                       T key, Comparator<? super T> c) {
        rangeCheck(a.length, fromIndex, toIndex);
        return binarySearch0(a, fromIndex, toIndex, key, c);
    }

二分查找的泛型实现,使用二分搜索法来搜索指定数组的范围,以获得指定对象。

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;
    }

此方法为如果两个指定的 Objects 数组彼此相等,则返回 true。在具体的实现中如果两个Objects中有1个为null则返回false。

 

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

此方法表示将指定的 Object 引用分配给指定 Object 数组的每个元素。

public static <T> T[] copyOf(T[] original, int newLength) {
        return (T[]) copyOf(original, newLength, original.getClass());
}

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;
    }

复制指定的数组,截取或用 null 填充(如有必要),以使副本具有指定的长度。这里注意对泛型的使用。,最终调用System.arraycopy函数进行复制操作。

public static <T> T[] copyOfRange(T[] original, int from, int to) {
        return copyOfRange(original, from, to, (Class<T[]>) original.getClass());
}

public static <T,U> T[] copyOfRange(U[] original, int from, int to, Class<? extends T[]> newType) {
        int newLength = to - from;
        if (newLength < 0)
            throw new IllegalArgumentException(from + " > " + to);
        T[] copy = ((Object)newType == (Object)Object[].class)
            ? (T[]) new Object[newLength]
            : (T[]) Array.newInstance(newType.getComponentType(), newLength);
        System.arraycopy(original, from, copy, 0,
                         Math.min(original.length - from, newLength));
        return copy;
    }

将指定数组的指定范围复制到一个新数组。

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

    /**
     * @serial include
     */
    private static class ArrayList<E> extends AbstractList<E>
        implements RandomAccess, java.io.Serializable
    {
        private static final long serialVersionUID = -2764017481108945198L;
        private final E[] a;

        ArrayList(E[] array) {
            if (array==null)
                throw new NullPointerException();
            a = array;
        }

        public int size() {
            return a.length;
        }

        public Object[] toArray() {
            return a.clone();
        }

        public <T> T[] toArray(T[] a) {
            int size = size();
            if (a.length < size)
                return Arrays.copyOf(this.a, size,
                                     (Class<? extends T[]>) a.getClass());
            System.arraycopy(this.a, 0, a, 0, size);
            if (a.length > size)
                a[size] = null;
            return a;
        }

        public E get(int index) {
            return a[index];
        }

        public E set(int index, E element) {
            E oldValue = a[index];
            a[index] = element;
            return oldValue;
        }

        public int indexOf(Object o) {
            if (o==null) {
                for (int i=0; i<a.length; i++)
                    if (a[i]==null)
                        return i;
            } else {
                for (int i=0; i<a.length; i++)
                    if (o.equals(a[i]))
                        return i;
            }
            return -1;
        }

        public boolean contains(Object o) {
            return indexOf(o) != -1;
        }
    }

返回一个受指定数组支持的固定大小的列表。@SafeVarargs注解抑制编译器警告的示例,只能用在参数长度可变的方法或构造方法上,且方法必须声明为static或final,否则会出现编译错误。一个方法使用@SafeVarargs注解的前提是,开发人员必须确保这个方法的实现中对泛型类型参数的处理不会引发类型安全问题。

public static int hashCode(Object a[]) {
        if (a == null)
            return 0;

        int result = 1;

        for (Object element : a)
            result = 31 * result + (element == null ? 0 : element.hashCode());

        return result;
    }

基于指定数组的内容返回哈希码。这个方法继承自java.lang.Object。

public static int deepHashCode(Object a[]) {
        if (a == null)
            return 0;

        int result = 1;

        for (Object element : a) {
            int elementHash = 0;
            if (element instanceof Object[])
                elementHash = deepHashCode((Object[]) element);
            else if (element instanceof byte[])
                elementHash = hashCode((byte[]) element);
            else if (element instanceof short[])
                elementHash = hashCode((short[]) element);
            else if (element instanceof int[])
                elementHash = hashCode((int[]) element);
            else if (element instanceof long[])
                elementHash = hashCode((long[]) element);
            else if (element instanceof char[])
                elementHash = hashCode((char[]) element);
            else if (element instanceof float[])
                elementHash = hashCode((float[]) element);
            else if (element instanceof double[])
                elementHash = hashCode((double[]) element);
            else if (element instanceof boolean[])
                elementHash = hashCode((boolean[]) element);
            else if (element != null)
                elementHash = element.hashCode();

            result = 31 * result + elementHash;
        }

        return result;
    }

基于指定数组的“深层内容”返回哈希码。

public static boolean deepEquals(Object[] a1, Object[] a2) {
        if (a1 == a2)
            return true;
        if (a1 == null || a2==null)
            return false;
        int length = a1.length;
        if (a2.length != length)
            return false;

        for (int i = 0; i < length; i++) {
            Object e1 = a1[i];
            Object e2 = a2[i];

            if (e1 == e2)
                continue;
            if (e1 == null)
                return false;

            // Figure out whether the two elements are equal
            boolean eq = deepEquals0(e1, e2);

            if (!eq)
                return false;
        }
        return true;
    }

如果两个指定数组彼此是深层相等 的,则返回 true

public static String toString(Object[] 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(String.valueOf(a[i]));
            if (i == iMax)
                return b.append(']').toString();
            b.append(", ");
        }
    }

返回指定数组内容的字符串表示形式。

public static String deepToString(Object[] a) {
        if (a == null)
            return "null";

        int bufLen = 20 * a.length;
        if (a.length != 0 && bufLen <= 0)
            bufLen = Integer.MAX_VALUE;
        StringBuilder buf = new StringBuilder(bufLen);
        deepToString(a, buf, new HashSet<Object[]>());
        return buf.toString();
    }

返回指定数组“深层内容”的字符串表示形式。

3.  Arrays类的使用

一般主要使用Arrays类进行排序和查找,下面是简单的使用例子

import java.util.Arrays;
import java.util.Random;

class RandomString {
	private RandomString() {}
	public static String getString(int length) {
		String base = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
		Random random = new Random();
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < length; i++) {
			int index = random.nextInt(base.length());
			sb.append(base.charAt(index));
		}
		return sb.toString();
	}
}

public class ArraysTest {
	public static void main(String[] args) {
		int[] intArray = new int[10000000];
		String[] stringArray = new String[10000000];
		Random random = new Random();
		
		// sort test
		for (int i = 0; i < intArray.length; i++) {
			intArray[i] = random.nextInt(1000000);
		}
		for (int j = 0; j < stringArray.length; j++) {
			stringArray[j] = RandomString.getString(random.nextInt(20));
		}
		long startTime = System.currentTimeMillis();
		Arrays.sort(intArray);
		long endTime = System.currentTimeMillis();
		System.out.println("sort int numbers cost: " + (endTime - startTime) + "ms");
		
		startTime = System.currentTimeMillis();
		Arrays.sort(stringArray);
		endTime = System.currentTimeMillis();
		System.out.println("sort string numbers cost: " + (endTime - startTime) + "ms");
		//System.out.println(Arrays.toString(stringArray));
		
		// search test
		startTime = System.nanoTime();
		Arrays.binarySearch(intArray, 97);
		endTime = System.nanoTime();
		System.out.println("search the numbers cost: " + (endTime - startTime) + "ns");
		
		startTime = System.nanoTime();
		Arrays.binarySearch(stringArray, "abcdef");
		endTime = System.nanoTime();
		System.out.println("search the numbers cost: " + (endTime - startTime) + "ns");
	}
}

可以看到在使用Arrays类的sort和二分查找函数时,当给10000000个整数和10000000个字符串排序并且做查找时消耗时间如下

sort int numbers cost: 1123ms
sort string cost: 13713ms
search the numbers cost: 15789ns
search the string cost: 39474ns

 


 

posted on 2014-10-31 01:36  elvalad  阅读(1731)  评论(0编辑  收藏  举报