java集合类源码学习二

  我们查看Collection接口的hierarchy时候,可以看到AbstractCollection<E>这样一个抽象类,它实现了Collection接口的部分方法,Collection集合系列的各个集合类都继承于该抽象类。我们来看看这个类:

public abstract class AbstractCollection<E> implements Collection<E> {
  
    protected AbstractCollection() {
    }

    public abstract Iterator<E> iterator();

    public abstract int size();

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

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

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

    @SuppressWarnings("unchecked")
    public <T> T[] toArray(T[] a) {
        // Estimate size of array; be prepared to see more or fewer elements
        int size = size();
        T[] r = a.length >= size ? a :
                  (T[])java.lang.reflect.Array
                  .newInstance(a.getClass().getComponentType(), size);
        Iterator<E> it = iterator();

        for (int i = 0; i < r.length; i++) {
            if (! it.hasNext()) { // fewer elements than expected
                if (a == r) {
                    r[i] = null; // null-terminate
                } else if (a.length < i) {
                    return Arrays.copyOf(r, i);
                } else {
                    System.arraycopy(r, 0, a, 0, i);
                    if (a.length > i) {
                        a[i] = null;
                    }
                }
                return a;
            }
            r[i] = (T)it.next();
        }
        // more elements than expected
        return it.hasNext() ? finishToArray(r, it) : r;
    }

    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    @SuppressWarnings("unchecked")
    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);
    }

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

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

    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;
    }
   
    public boolean containsAll(Collection<?> c) {
        for (Object e : c)
            if (!contains(e))
                return false;
        return true;
    }

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

    public boolean removeAll(Collection<?> c) {
        Objects.requireNonNull(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) {
        Objects.requireNonNull(c);
        boolean modified = false;
        Iterator<E> it = iterator();
        while (it.hasNext()) {
            if (!c.contains(it.next())) {
                it.remove();
                modified = true;
            }
        }
        return modified;
    }

    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(' ');
        }
    }

}
    

   从它的代码里我们可以看到,它有一个最大长度,是Integer的最大值减去8,至于为什么减8,是因为有些JVM会在数组里保存几个关键字符。我们再看这个contains方法,我很好奇的是,既然参数是Object类型,那么就包括了null,为什么判断的时候还要把null单独拿出来,这个疑问不知哪个大佬能给我解释一下。

  再看toArray的不带参方法,new了一个和size()方法表示的长度一样长的Object数组r,还弄了一个迭代器出来,然后用for来循环r数组的每一个下标,并在每一次循环中判断迭代器的hasNext()是否为false,如果为false则说明当前集合长度比r数组短,则用Array的copyOf()方法把r数组放到一个长度为i的数组里,这样就不浪费多余的空间了。最后判断如果hasNext()还为true,则说明当前集合长度比r数组长,就用finishToArray()方法返回一个Object数组。至于为什么比较过和size()的大小之后还有这种操作,上面注释有说明,是迭代的时候假如对元素有增删操作,会导致长度有变化。finishToArray(T[] r, Iterator<?> it)方法把数组r扩容之后往里面添加迭代器后续元素,可以看到hugeCapacity这个玩意,当数组长度超过Integer最大值减8的时候,就用Integer的最大值,这样数组的长度是不能超过2^31的,毕竟数组下标使用int数字表示的。带参的toArray方法差不多意思,是可以将集合转化成指定类型的数组。

  add()方法会直接抛出异常,说明AbstractCollection是不允许添加元素的,那么一定是在具体实现类里实现的这个方法。至于其他的方法,看一下就明白了。

  接着我们来看看public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E>,这是list的抽象类,继承自AbstractCollection,实现List接口的部分方法。源码就不贴了,现在重点来看一下内部类Itr,这是一个迭代器的实现类。里面定义了三个变量:游标cursor、最近一次调用返回的索引lastRet和期望得到的修改次数expectedModCount。里面实现了迭代器的三个方法,注意next()和remove()方法里都调用了这么一个方法checkForComodification(),这个用来比较expectedModCount和modCount,如果不同就抛出异常ConcurrentModificationException,这个意思是如果在迭代操作的时候,如果有用非迭代器的操作对集合做了修改,那么就会抛出异常。对于modCount,我们可以在AbstractList的子类中看到,每次对集合做了操作,modCount就会加一。

public static void main(String[] args) {
		List<Integer> list = new ArrayList<Integer>();
		list.add(11);
		list.add(12);
		list.add(13);
		list.add(14);
		list.add(15);
		Iterator<Integer> itr = list.iterator();
		while(itr.hasNext()) {
			if(itr.next() == 13) {
				itr.remove();
			}
		}
		System.out.println(list);
	}

  在迭代的时候用迭代器的remove操作就不会报错,如果在增强for循环中,用了ArrayList自带的remove,就会报异常了。下面的内部类ListItr是一个ListIterator的实现类,可以往前往后迭代,还有多了几个方法,代码都很简单。subList()截取一段子序列,支持往前往后截取。下面还有个SubList类,里面有个往后截取一段子序列的方法,其他的起始都是用的父类的方法。

posted @ 2018-01-05 15:12  fengshenjingjun  阅读(257)  评论(0编辑  收藏  举报