java集合分析(4):AbstractCollection

来源:互联网 发布:网络捕鱼游戏原理 编辑:程序博客网 时间:2024/06/05 05:57

在上一篇中我们学习了Collection的基本概念和用法,这篇我们来看看实现了Collection接口的抽象类AbstractCollection。

AbstractCollection

直接实现Collection接口的类只有AbstractCollection类,该类是一个抽象类,提供了对集合类操作的一些基本实现。List和Set的具体实现类基本上都直接或间接的继承了该类;
如果想要实现一个不可修改的Collection,只需要继承AbstractCollection并且实现两个抽象方法即可;
如果想要实现可以修改的Collection,还需要重写add()方法和iterator()方法返回的迭代器实现remove()方法;
下面我们来看看AbstractCollection内部的具体实现:

 public abstract Iterator<E> iterator(); public abstract int size();

可以看到这两个是抽象方法,没有具体实现,让子类去复写。

isEmpty

public boolean isEmpty() {        return size() == 0;}

直接调用size()(这个size()在AbstractCollection中是空实现,具体实现是在子类中)方法返回大小,如果是0就认为是空集合.

contains

 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源码可以看到 , contains方法里是先调用自己iterator(这个iterator在AbstractCollection中是空实现,具体实现是在子类中)方法来遍历集合,并且是先判断传来的参数是否null.然后在做具体的实现.

toArray()

public Object[] toArray() {        // Estimate size of array; be prepared to see more or fewer elements        Object[] r = new Object[size()];        Iterator<E> it = iterator();        for (int i = 0; i < r.length; i++) {            if (! it.hasNext()) // fewer elements than expected                return Arrays.copyOf(r, i);            r[i] = it.next();        }        return it.hasNext() ? finishToArray(r, it) : r;    }

从上面源码可以看到,内部实现是先根据size()的大小生成一个数组,然后获取Iterator迭代器, 在通过hasNext来判断当前迭代器后面还有没有值,如果有就赋值给数组 r;
if (! it.hasNext())这段代码判断当前迭代器实际迭代数量的大小比size()小,如果成立, 就直接通过Arrays.copyOf来复制当前数组r,然后直接返回;
通过上面for循环之后,如果if (! it.hasNext())不成立,那么r数组的大小就是size大小,但最后这段代码 [return it.hasNext() ? finishToArray(r, it) : r],意思是如果当前迭代器it.hasNext()后面还有值,也就是size的大小小于迭代器迭代的数量 , 就调用finishToArray来完成之后迭代器的实现,否则就直接返回数组 r .

finishToArray

    private static <T> T[] finishToArray(T[] r, Iterator<?> it) {        int i = r.length;        while (it.hasNext()) {            int cap = r.length;            if (i == cap) {                int newCap = cap + (cap >> 1) + 1;                // overflow-conscious code                if (newCap - MAX_ARRAY_SIZE > 0)                    newCap = hugeCapacity(cap + 1);                r = Arrays.copyOf(r, newCap);            }            r[i++] = (T)it.next();        }        // trim if overallocated        return (i == r.length) ? r : Arrays.copyOf(r, i);    }

我们可以看到每次进入循环体,先用cap确认下数组的长度。如果i还没有增长到cap相同的程度则只要将迭代器的下一个元素放入数组并将i加一就行; 如果i==cap的时候说明需要增大cap。这里增加的cap的一半并加1的大小,然后判断下新的数组的大小是否超过VM的最大界限,如果没有就将继续循环体; 在返回的时候使用根据已经迭代的元素i来复制当前数组到一个新的数组中 ; 这里如果判断newCap大小超过了最大的数组大小则调动hugeCapacity调整大小。这里需要说明在AbstractCollection类中间声明了一个静态私有常量MAX_ARRAY_SIZE数值为Integer.MAX_VALUE - 8。按照源码里的说明是虚拟机通常会放几个头信息在数组中。

hugeCapacity

  private static int hugeCapacity(int minCapacity) {        if (minCapacity < 0) // overflow            throw new OutOfMemoryError                ("Required array size too large");        return (minCapacity > MAX_ARRAY_SIZE) ?            Integer.MAX_VALUE :            MAX_ARRAY_SIZE;    }

如果当前的cap最大值不可在继续增大,即cap+1为负值则抛出一个超出内存大小的异常。
如果当前的值可以分配,则分配一个MAX_ARRAY_SIZE和MAX_VALUE 中的满足条件的值。

remove() 删除某个元素:

public boolean remove(Object o) {        Iterator<E> it = iterator();        if (o==null) {            while (it.hasNext()) {                if (it.next()==null) {                    it.remove();                    return true;                }            }        } else {            while (it.hasNext()) {                if (o.equals(it.next())) {                    it.remove();                    return true;                }            }        }        return false;    }

removeAll() 删除指定集合中包含在本集合的元素:

   public boolean removeAll(Collection<?> c) {        boolean modified = false;        Iterator<?> it = iterator();        while (it.hasNext()) {            if (c.contains(it.next())) {                it.remove();                modified = true;            }        }        return modified;    }

保留共有的,删除指定集合中不共有的

  public boolean retainAll(Collection<?> c) {        boolean modified = false;        Iterator<E> it = iterator();        while (it.hasNext()) {            if (!c.contains(it.next())) {                it.remove();                modified = true;            }        }        return modified;    }

toString() 把内容转换成一个 String 进行展示:

public String toString() {    if (isEmpty()) {        return "[]";    }    //注意默认容量是 size() 的 16 倍,为什么是 16 呢?    StringBuilder buffer = new StringBuilder(size() * 16);    buffer.append('[');    //仍旧用到了迭代器    Iterator<?> it = iterator();    while (it.hasNext()) {        Object next = it.next();        if (next != this) {            //这个 Object 也得重写 toString() 方法,不然不能输出内容            buffer.append(next);        } else {            buffer.append("(this Collection)");        }        if (it.hasNext()) {            buffer.append(", ");        }    }    buffer.append(']');    return buffer.toString();}
ArrayList<String> list = new ArrayList<>();        list.add("a");        list.add("b");        list.add("c");        System.out.println(list);

输出结果:[a, b, c]
可以看出System.out.print(list) 直接输出集合的全部内容,而不用挨个遍历输出,全是因为 AbstractCollection 的toString() 方法。

add(E e)

 public boolean add(E e) {        throw new UnsupportedOperationException();    }

可以看出,AbstractCollection 中默认不支持添加单个元素,如果直接调用 add(E) 方法,就会报错,因此,如果子类是可添加的数据结构,需要自己实现 add(E) 方法。

addAll 添加一个集合内的全部元素:

  public boolean addAll(Collection<? extends E> c) {        boolean modified = false;        for (E e : c)            if (add(e))                modified = true;        return modified;    }

Thank:

http://blog.csdn.net/u011518120/article/details/51924587

原创粉丝点击