Java集合源码分析之超级接口:Collection_一点课堂(多岸学院)

Collection

CollectionListQueueSet的超集,它直接继承于Iterable,也就是全部的Collection集合类都支持for-each循环。除此以外,Collection也是面向接口编程的典范,经过它能够在多种实现类间转换,这也是面向对象编程的魅力之一。java

方法定义

在阅读源码前,咱们能够先自行想象一下,若是咱们想封装下数组或链表以方便操做,咱们须要封装哪些功能呢?好比:统计大小、插入或删除数据、清空、是否包含某条数据,等等。而Collection就是对这些经常使用操做进行提取,只是其很全面、很通用。下面咱们看看它都提供了哪些方法。编程

//返回集合的长度,若是长度大于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;
}

超级实现类:AbstractCollection

Collection中定义的许多方法,根据现有的定义以及继承的Iterable,均可以在抽象类中实现,这样能够减小实现类须要实现的方法,这个抽象类就是AbstractCollection数组

首先咱们关注下其文档,里面有两句说明可能会影响咱们的继承:app

To implement an unmodifiable collection, the programmer needs only to extend this class and provide implementations for the iterator and size methods. (The iterator returned by the iterator method must implement hasNext and next.)ide

To implement a modifiable collection, the programmer must additionally override this class's add method (which otherwise throws an UnsupportedOperationException), and the iterator returned by the iterator method must additionally implement its remove method.学习

大致意思是说,若是要实现一个不可修改的集合,只须要重写iteratorsize接口就能够,而且返回的Iterator须要实现hasNextnext。而要实现一个能够修改的集合,还必须重写add方法(默认会抛出异常),返回的Iterator还须要实现remove方法。ui

方法定义

//这个毫无疑问,是能够直接获取的
public boolean isEmpty() {
    return size() == 0;
}

//这个方法由于Iterator的存在,能够进行一致性封装,这里须要注意的是对象的比较是经过equals方法,由于调用到了it.next()与it.hasNext(),这也是为何文档注释会写实现集合类须要重写Iterator的这两个方法。
public boolean contains(Object o) {
    Iterator<E> it = iterator();
    if (o==null) {
        while (it.hasNext())
            if (it.next()==null)
                return true;
    } else {
        while (it.hasNext())
            if (o.equals(it.next()))
                return true;
    }
    return false;
}

//和contains相似,也是经过Iterator实现的,但其会调用it.remove()方法,这也是为何文档注释会写实现能够修改的集合类时须要重写Iterator的remove方法。
public boolean remove(Object o) {
    //...省略,这里调用了it.remove()方法
}

相似的方法还有containsAll(Collection<?> c)addAll(Collection<? extends E> c)removeAll(Collection<?> c)retainAll(Collection<?> c)clear()等,都须要利用到Iterator的特性,这里就再也不一一赘述了。this

另外还有一个toArray()的方法实现略微不一样,能够看看其具体实现。3d

//这个实现相对复杂一些,能够看到扩容最主要的手段是Arrays.copyOf()方法,
//也就是须要将原数组经过复制到新的数组中来实现的。
//注意这里返回的顺序和Iterator顺序一致
//在这里实现是为了方便不一样具体实现类互相转换,咱们在后续会屡次见到此方法
public Object[] toArray() {
    //先根据当前集合大小声明一个数组
    Object[] r = new Object[size()];
    Iterator<E> it = iterator();
    for (int i = 0; i < r.length; i++) {
        //集合元素没那么多,说明不须要那么大的数组
        if (! it.hasNext()) 
            return Arrays.copyOf(r, i); //仅返回赋完值的部分
        r[i] = it.next();
    }
    //元素比从size()中获取的更多,就须要进一步调整数组大小
    return it.hasNext() ? finishToArray(r, it) : r;
}

private static <T> T[] finishToArray(T[] r, Iterator<?> it) {
    //记录当前大小
    int i = r.length;
    while (it.hasNext()) {
        int cap = r.length;
        //r的长度不够,继续分配
        if (i == cap) {
            //扩充方式为cap+cap/2+1,也就是1.5倍扩容
            int newCap = cap + (cap >> 1) + 1;
            // 超过了最大容量,MAX_ARRAY_SIZE=Integer.MAX_VALUE-8
            if (newCap - MAX_ARRAY_SIZE > 0)
                //从新设置cap的值
                newCap = hugeCapacity(cap + 1);
            
            //对r进行扩容
            r = Arrays.copyOf(r, newCap);
        }
        //赋值,进入下一轮循环
        r[i++] = (T)it.next();
    }
    // 因为以前扩容是1.5倍进行的,最后再将其设置到和r实际须要的相同
    return (i == r.length) ? r : Arrays.copyOf(r, i);
}

private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) // 超过了最大正整数,也就是负数
        throw new OutOfMemoryError
            ("Required array size too large");
    return (minCapacity > MAX_ARRAY_SIZE) ?
        Integer.MAX_VALUE :
        MAX_ARRAY_SIZE;
}

//和toArray()方法相似,就再也不赘述,具体能够查看源码
public <T> T[] toArray(T[] a) {
    //...
}

除了以上这些方法,AbstractCollection还实现了toString方法,其是经过StringBuilder拼接了每一个元素的toString完成的,也并不复杂。这里能够看下其源码:code

public String toString() {
    Iterator<E> it = iterator();
    if (! it.hasNext())
        return "[]";

    StringBuilder sb = new StringBuilder();
    sb.append('[');
    for (;;) {
        E e = it.next();
        sb.append(e == this ? "(this Collection)" : e);
        if (! it.hasNext())
            return sb.append(']').toString();
        sb.append(',').append(' ');
    }
}

【感谢您能看完,若是可以帮到您,麻烦点个赞~】

更多经验技术欢迎前来共同窗习交流: 一点课堂-为梦想而奋斗的在线学习平台 http://www.yidiankt.com/

![关注公众号,回复“1”免费领取-【java核心知识点】] file

QQ讨论群:616683098

QQ:3184402434

想要深刻学习的同窗们能够加我QQ一块儿学习讨论~还有全套资源分享,经验探讨,等你哦! 在这里插入图片描述

相关文章
相关标签/搜索