源码分析之Collection

 

Collection

  Collection是List、Queue和Set的超集,它直接继承于Iterable,也就是所有的Collection集合类都支持for-each循环。

public interface Collection<E> extends Iterable<E> {
    //返回集合的长度,如果长度大于Integer.MAX_VALUE,返回 //返回集合的长度,如果长度大于Integer.MAX_VALUE,返回Integer.MAX_VALUE
    int size();

    //如果集合元素总数为0,返回true
    boolean isEmpty();

    //判断集合中是否包含指定的元素,其依据是equals()方法
    boolean contains(Object o);

    //返回一个包含集合中所有元素的数组
    Object[] toArray();

    //与上个类似,只是增加了类型的转换
    <T> T[] toArray(T[] a);

    //向集合中加入一个元素,如果成功加入则返回true,如果加入失败,或者因集合本身已经包含同个元素而不再加入时,返回false
    boolean add(E e);

    //从集合中删除指定元素的单个实例
    boolean remove(Object o);

    //如果集合包含指定集合中的所有元素,返回true
    boolean containsAll(Collection<?> c);

    //把指定集合中的所有元素添加到集合中,但在此期间,如果指定的集合发生了改变,可能出现意想不到的事情
    boolean addAll(Collection<? extends E> c);

    //从集合中删除所有包含在指定集合中的元素
    boolean removeAll(Collection<?> c);

    //仅保留集合中包含在指定集合中的元素
    boolean retainAll(Collection<?> c);

    //清空集合
    void clear();

    //将此方法抽象,是保证所有子类都覆写此方法,以保证equals的正确行为
    boolean equals(Object o);

    //同上
    int hashCode();

    //这个方法在JDK1.8中提供了默认的实现,会使用Iterator的形式删除符合条件的元素
    default boolean removeIf(Predicate<? super E> filter){
        Objects.requireNonNull(filter);
        boolean removed = false;
        final Iterator<E> each = iterator();
        while (each.hasNext()) {
            if (filter.test(each.next())) {
                each.remove();
                removed = true;
            }
        }
        return removed;
    }
}
View Code

Collections

  Collections 是一个操作 Set、List 和 Map 等集合的工具类。Collections 中提供了一系列静态的方法对集合元素进行排序、查询和修改等操作,还提供了对集合对象设置不可变、对集合对象实现同步控制等方法。

  Collections 类中提供了多个 synchronizedXXX() 方法,该方法可使指定集合包装成线程同步的集合,从而可以解决多线程并发访问集合时的线程安全问题。

static <T> Set<T> synchronizedSet(Set<T> s) {
     return new SynchronizedSet<>(s);
} 

  Collections提供了三类方法返回一个不可变集合:

emptyXXX() :返回一个空的只读集合
singleXXX():返回一个只包含指定对象,只有一个元素,只读的集合。
unmodifiablleXXX():返回指定集合对象的只读视图。

  Collections提供了sort方法对集合进行排序:

public static <T> void sort(List<T> list):将集合中元素按照默认规则排序。默认是升序
public static <T> void sort(List<T> list,Comparator<? super T> ):将集合中元素按照指定规则排序。

 

Comparator源码解析

示例:compare()结果小于0,顺序反转

class TimSort<T> {
    /**
     *
     * @param a the array to be sorted
     * @param lo the index of the first element, inclusive, to be sorted
     * @param hi the index of the last element, exclusive, to be sorted
     * @param c the comparator to use
     * @param work a workspace array (slice)  默认null
     * @param workBase origin of usable space in work array  默认0
     * @param workLen usable size of work array  默认0
     * @since 1.8
     */
    static <T> void sort(T[] a, int lo, int hi, Comparator<? super T> c, T[] work, int workBase, int workLen) {
        assert c != null && a != null && lo >= 0 && lo <= hi && hi <= a.length;
        int nRemaining  = hi - lo;
        if (nRemaining < 2)
            return;  // Arrays of size 0 and 1 are always sorted
        // If array is small, do a "mini-TimSort" with no merges.  MIN_MERGE = 32
        if (nRemaining < MIN_MERGE) { 
            int initRunLen = countRunAndMakeAscending(a, lo, hi, c);
            binarySort(a, lo, hi, lo + initRunLen, c);
            return;
        }
        /**
         * March over the array once, left to right, finding natural runs,extending short natural runs to minRun elements, and merging runs to maintain stack invariant.
         */
        TimSort<T> ts = new TimSort<>(a, c, work, workBase, workLen);
        int minRun = minRunLength(nRemaining);
        do {
            // Identify next run
            int runLen = countRunAndMakeAscending(a, lo, hi, c);
            // If run is short, extend to min(minRun, nRemaining)
            if (runLen < minRun) {
                int force = nRemaining <= minRun ? nRemaining : minRun;
                binarySort(a, lo, lo + force, lo + runLen, c);
                runLen = force;
            }
            // Push run onto pending-run stack, and maybe merge
            ts.pushRun(lo, runLen);
            ts.mergeCollapse();

            // Advance to find next run
            lo += runLen;
            nRemaining -= runLen;
        } while (nRemaining != 0);
        // Merge all remaining runs to complete sort
        assert lo == hi;
        ts.mergeForceCollapse();
        assert ts.stackSize == 1;
    }

    /**
     * Returns the length of the run beginning at the specified position in the specified array and reverses the run if it is descending (ensuring that the run will always be     * ascending when the method returns).对集合从第0位开始进行检查,如果在第p位出现前后顺序不一致(例如1,5,3),则停止检查,并返回p。如果第0位至第p位中compare(o1,o2)<0,则进行冒泡反转排序。确保结果升序
     *
     * A run is the longest ascending sequence with: a[lo] <= a[lo + 1] <= a[lo + 2] <= ...
     * or the longest descending sequence with: a[lo] >  a[lo + 1] >  a[lo + 2] >  ...
     *
     * For its intended use in a stable mergesort, the strictness of the definition of "descending" is needed so that the call can safely
     * reverse a descending sequence without violating stability.
     *
     * @param a the array in which a run is to be counted and possibly reversed
     * @param lo index of the first element in the run
     * @param hi index after the last element that may be contained in the run.
              It is required that {@code lo < hi}.
     * @param c the comparator to used for the sort
     * @return  the length of the run beginning at the specified position in the specified array
     */
    private static <T> int countRunAndMakeAscending(T[] a, int lo, int hi, Comparator<? super T> c) {
        assert lo < hi;
        int runHi = lo + 1;
        if (runHi == hi)
            return 1;

        // Find end of run, and reverse range if descending 
        if (c.compare(a[runHi++], a[lo]) < 0) { // Descending 可以看到compare的第一个参数是集合中后面的数据,第二个参数是集合中前面的数
            while (runHi < hi && c.compare(a[runHi], a[runHi - 1]) < 0)
                runHi++;
            reverseRange(a, lo, runHi);
        } else {                              // Ascending
            while (runHi < hi && c.compare(a[runHi], a[runHi - 1]) >= 0)
                runHi++;
        }
        return runHi - lo;
    }

    /**
     * Reverse the specified range of the specified array. 冒泡排序
     *
     * @param a the array in which a range is to be reversed
     * @param lo the index of the first element in the range to be reversed
     * @param hi the index after the last element in the range to be reversed
     */
    private static void reverseRange(Object[] a, int lo, int hi) {
        hi--;
        while (lo < hi) {
            Object t = a[lo];
            a[lo++] = a[hi];
            a[hi--] = t;
        }
    }


/**
     * Sorts the specified portion of the specified array using a binary insertion sort.  This is the best method for sorting small numbers of elements.       * It requires O(n log n) compares, but O(n^2) data movement (worst case).
     * If the initial part of the specified range is already sorted, this method can take advantage of it: the method assumes that the
     * elements from index {@code lo}, inclusive, to {@code start}, exclusive are already sorted.
     *
     * @param a the array in which a range is to be sorted
     * @param lo the index of the first element in the range to be sorted
     * @param hi the index after the last element in the range to be sorted
     * @param start the index of the first element in the range that is
     *        not already known to be sorted ({@code lo <= start <= hi})
     * @param c comparator to used for the sort
     */
    @SuppressWarnings("fallthrough")
    private static <T> void binarySort(T[] a, int lo, int hi, int start,Comparator<? super T> c) {
        assert lo <= start && start <= hi;
        if (start == lo)
            start++;
        for ( ; start < hi; start++) {
            T pivot = a[start];
            // Set left (and right) to the index where a[start] (pivot) belongs
            int left = lo;
            int right = start;
            assert left <= right;
            /*
             * Invariants:
             *   pivot >= all in [lo, left).
             *   pivot <  all in [right, start).
             */
            while (left < right) {
                int mid = (left + right) >>> 1;
                if (c.compare(pivot, a[mid]) < 0)
                    right = mid;
                else
                    left = mid + 1;
            }
            assert left == right;

            /*
             * The invariants still hold: pivot >= all in [lo, left) and pivot < all in [left, start), so pivot belongs at left.  Note
             * that if there are elements equal to pivot, left points to the first slot after them -- that's why this sort is stable.
             * Slide elements over to make room for pivot.
             */
            int n = start - left;  // The number of elements to move
            // Switch is just an optimization for arraycopy in default case
            switch (n) {
                case 2:  a[left + 2] = a[left + 1];
                case 1:  a[left + 1] = a[left];
                         break;
                default: System.arraycopy(a, left, a, left + 1, n);
            }
            a[left] = pivot;
        }
    }

}
View Code

 

posted @ 2021-01-22 15:11  鄙人取个名字好难  阅读(63)  评论(0编辑  收藏  举报