【java源码阅读】java.util.Collections

1. 简介

Collections是util包中一个不可实例化(non-instantiability)的类。

   // Suppresses default constructor, ensuring non-instantiability.
    private Collections() {
    }

2. 源码阅读

2.1 优化参数

    private static final int BINARYSEARCH_THRESHOLD   = 5000;
    private static final int REVERSE_THRESHOLD        =   18;
    private static final int SHUFFLE_THRESHOLD        =    5;
    private static final int FILL_THRESHOLD           =   25;
    private static final int ROTATE_THRESHOLD         =  100;
    private static final int COPY_THRESHOLD           =   10;
    private static final int REPLACEALL_THRESHOLD     =   11;
    private static final int INDEXOFSUBLIST_THRESHOLD =   35;

我们首先就可以看见Collecions定义的各种变量,这些变量叫做优化参数(Tuning Parameter),其作用在于优化类中方法的性能(permformance),之后再讲解方法时我们可以看到。

THRESHOLD有门槛的意思

2.2 sort

@SuppressWarnings("unchecked")用于屏蔽编译器的警告信息,比如强制类型转换时。

    @SuppressWarnings("unchecked")

     //<T extends Comparable<? super T>> 表示若想对list使用sort方法,那么list其中对象(或者其对象的父类)必须继承Comparable这个类,并且实现其方法。
    public static <T extends Comparable<? super T>> void sort(List<T> list) {
        
        //先将list转化为数组,再对数组进行排序。这样做的理由在于如果此list为`LinkedList`,那我们直接对其进行排序的话时间复杂度就会变为n*n*log(n)
        //这里排序使用的算法是mergesort(归并排序),这需要留意mergesort是stable sort,即相等值得顺序不会改变。其他的详细解释可以参考我另一篇关于mergesort的博文。
        Object[] a = list.toArray();
        Arrays.sort(a);

        //将排序好的结果赋值进原list
        ListIterator<T> i = list.listIterator();
        for (int j=0; j<a.length; j++) {
            i.next();
            i.set((T)a[j]);
        }
    }

@SuppressWarnings({"unchecked", "rawtypes"}),rawtypes表示类的参数上使用泛型时所出现的警告信息。

    @SuppressWarnings({"unchecked", "rawtypes"})

    //传入包含对象T的list及其(或其父类的)比较器Comparator
    public static <T> void sort(List<T> list, Comparator<? super T> c) {
        
        //也先转换为数组,理由同上
        Object[] a = list.toArray();
        Arrays.sort(a, (Comparator)c);

        //同上
        ListIterator<T> i = list.listIterator();
        for (int j=0; j<a.length; j++) {
            i.next();
            i.set((T)a[j]);
        }
    }

此部分的函数算法都是使用二分查找实现的,其特点也和二分查找一样:

  • 序列必须是有序的,无序序列不保证结果
  • 若查找的元素在序列中有多个,不能保证返回的是哪一个。
  //对象或其父类必须实现Comparable的方法
  public static <T>
  int binarySearch(List<? extends Comparable<? super T>> list, T key) {
        
        //RandomAccess 表示list提供常数时间的元素访问方法,在这里就表明其实一个数组列表。
        //如果list不是数组列表,只要其size小于BINARYSEARCH_THRESHOLD,也可以使用此搜索方法而不影响性能。
        if (list instanceof RandomAccess || list.size()<BINARYSEARCH_THRESHOLD)
            return Collections.indexedBinarySearch(list, key);
        else
        //size大于BINARYSEARCH_THRESHOLD的非数组列表调用此方法
            return Collections.iteratorBinarySearch(list, key);
    }
    private static <T>
    int indexedBinarySearch(List<? extends Comparable<? super T>> list, T key) {
        int low = 0;
        int high = list.size()-1;

        while (low <= high) {
            // >>> 为无符号右移移位运算符。这里表示将其向右移动一位(不考虑符号位),其效果等同于“除以2”,但是性能比直接使用除法性能好。
            int mid = (low + high) >>> 1;
            Comparable<? super T> midVal = list.get(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
    }
    private static <T>
    int iteratorBinarySearch(List<? extends Comparable<? super T>> list, T key)
    {
        int low = 0;
        int high = list.size()-1;
        ListIterator<? extends Comparable<? super T>> i = list.listIterator();

        while (low <= high) {
            int mid = (low + high) >>> 1;
            
            //遍历查找ListIterator的第mid个元素
            Comparable<? super T> midVal = get(i, 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
    }
    private static <T> T get(ListIterator<? extends T> i, int index) {
        T obj = null;
        int pos = i.nextIndex();
        if (pos <= index) {
            do {
                obj = i.next();
            } while (pos++ < index);
        } else {
            do {
                obj = i.previous();
            } while (--pos > index);
        }
        return obj;
    }

2.4 reverse

//rawtypes指的是没有类型参数的泛型类或泛型接口
 @SuppressWarnings({"rawtypes", "unchecked"})
    public static void reverse(List<?> list) {
        int size = list.size();
        if (size < REVERSE_THRESHOLD || list instanceof RandomAccess) {
            for (int i=0, mid=size>>1, j=size-1; i<mid; i++, j--)
                swap(list, i, j);
        } else {
            ListIterator fwd = list.listIterator();
            ListIterator rev = list.listIterator(size);
            for (int i=0, mid=list.size()>>1; i<mid; i++) {
                Object tmp = fwd.next();
                fwd.set(rev.previous());
                rev.set(tmp);
            }
        }
    }

代码不难,和sort方法类似。主要的点在于一定要理解fwdrev指向的位置。 如下图所示,这两个指针指向的并不是元素而是元素之间的位置,通过调用next()/previous()方法来获得其前后的元素,并将其往前/后移动一位。

                  Element(0)   Element(1)   Element(2)   ... Element(n-1)

cursor positions: ^ ^ ^ ^ ^

2.5 shuffle

    @SuppressWarnings({"rawtypes", "unchecked"})
    public static void shuffle(List<?> list, Random rnd) {
        int size = list.size();
        if (size < SHUFFLE_THRESHOLD || list instanceof RandomAccess) {
            for (int i=size; i>1; i--)
                swap(list, i-1, rnd.nextInt(i));
        } else {
            Object arr[] = list.toArray();

            // Shuffle array
            for (int i=size; i>1; i--)
                swap(arr, i-1, rnd.nextInt(i));

            ListIterator it = list.listIterator();
            for (int i=0; i<arr.length; i++) {
                it.next();
                it.set(arr[i]);
            }
        }
    }

2.6 swap

   @SuppressWarnings({"rawtypes", "unchecked"})
    public static void swap(List<?> list, int i, int j) {
        //这里final表示的是l指向的对象list不能改变,但list其中的元素是可以改变的
        final List l = list;
        // 只需要注意一点,list的set命令会返回原先的值
        l.set(i, l.set(j, l.get(i)));
    }

    /**
     * Swaps the two specified elements in the specified array.
     */
    private static void swap(Object[] arr, int i, int j) {
        Object tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }
posted @ 2020-08-26 17:07  LinM狂想曲  阅读(208)  评论(0编辑  收藏  举报