JDK8源码阅读笔记
切换暗/亮/自动模式 切换暗/亮/自动模式 切换暗/亮/自动模式 返回首页

AbstractCollection



此类提供了Collection接口的基本实现,以最大程度地减少实现此接口所需的工作。

要实现一个不可修改的集合,编程者只需扩展此类并为iteratorsize方法提供实现。 (iterator方法返回的迭代器必须实现hasNextnext。)

要实现一个可修改的集合,编程者必须另外重写此类的add方法(否则将抛出UnsupportedOperationException),并且iterator方法返回的迭代器必须另外实现其remove方法。

Collection照接口规范中的建议,程序员通常应提供void(无参数)的Collection构造函数。

此类中每个非抽象方法的文档都详细描述了其实现。如果正在实现的集合有更有效的实现,则可以重写这些方法中的每一个。

该类是Java集合框架中的一员。

1. protected AbstractCollection()

唯一的构造函数。 (用于子类构造函数的调用,通常是隐式的。)

源码如下:

protected AbstractCollection() {
}

2. public abstract Iterator<E> iterator();

抽象方法,返回此集合中所包含元素的迭代器。

3. public abstract int size();

抽象方法,返回此集合所包含的元素数量。

4. public boolean isEmpty()

判断当前集合是否为空,底层是通过调用size()获取当前集合的元素数量,然后判断元素数量是否为0。

源码如下:

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

5. public boolean contains(Object o)

此实现对集合中的元素进行迭代,依次检查每个元素是否与参数中给定的元素相等。

使用该集合的迭代器遍历当前集合,如果参数中给定的参数onull,则判断当前集合中是否存在为null的元素。如果参数中给定的参数不为null,则通过equals判断当前集合中是否存在和给定元素o相等的元素。

源码如下:

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

6. public Object[] toArray()

此实现返回一个数组,该数组包含所有通过该集合的迭代器返回的元素,元素以相同的顺序在数组连续存在,从索引0开始。返回数组的长度等于迭代器返回的元素数(即使此集合的大小在迭代过程中发生了变化,如果该集合允许在迭代过程中进行并发修改,就可能会发生这种情况)。size方法仅作为优化提示被调用,即使迭代器返回不同数量的元素,也将返回正确的结果。

该方法等同于:

List<E> list = new ArrayList<E>(size());
for (E e : this)
    list.add(e);
return list.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();
		// 遍历当前集合,截止索引为当前集合的元素个数减1
    for (int i = 0; i < r.length; i++) {
				// 如果未遍历完却发现迭代器已迭代至末尾了,说明元素比期望的要少,此时也不报错,而是复制一个数组返回
        if (! it.hasNext()) // fewer elements than expected
            return Arrays.copyOf(r, i);
        r[i] = it.next();
    }
		// 如果遍历完成,但迭代器仍未至末尾,此时调用finishToArray方法重新分配数组并完成剩余元素的填充
    return it.hasNext() ? finishToArray(r, it) : r;
}

7. public <T> T[] toArray(T[] a)

此实现返回一个数组,此数组包含所有通过该集合的迭代器返回的元素,元素以相同的顺序在数组中连续存在,从索引0开始。如果迭代器返回的元素数量太多而无法容纳到指定的数组中,那么元素也会以新分配数组的形式返回,其长度等于迭代器返回的元素数量,即使此集合的大小发生变化(如果在迭代过程中集合允许并发修改,则可能会发生这种情况)。size方法仅作为优化提示被调用,即使迭代器返回不同数量的元素,也将返回正确的结果。

该方法等同于:

List<E> list = new ArrayList<E>(size());
for (E e : this)
    list.add(e);
return list.toArray();

源码如下:

@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
    // Estimate size of array; be prepared to see more or fewer elements
    int size = size();
		// 声明一个数组r,若指定数组a的容量大于等于集合的元素个数,说明数组a可以容纳当前集合的所有元素,此时r取指定的数组a
		// 否则,说明指定的数组a不足以容纳当前列表的所有元素,此时重新分配一个容量为当前集合元素个数的数组,并赋值给r
    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++) {
				// 未遍历结束,但迭代器已至末尾,说明集合的元素在toArray过程中变少了
        if (! it.hasNext()) { // fewer elements than expected
            if (a == r) {
								// 如果数组r就是指定的数组a,则此处第i个元素置为null
                r[i] = null; // null-terminate
            } else if (a.length < i) {
								// 进入此分支,说明在声明数组r的时候,r是新分配的数组,而非指定的a
								// 如果数组a的长度小于此处i,则复制一个数组返回
                return Arrays.copyOf(r, i);
            } else {
								// 进入此分支,说明在声明数组r的时候,r是新分配的数组,而非指定的a,且a的长度大于等于i,此时进行数组复制,把r复制给a
                System.arraycopy(r, 0, a, 0, i);
                if (a.length > i) {
										// 如果a的长度大于i,则i位置的元素置为null
                    a[i] = null;
                }
            }
						// 返回数组a
            return a;
        }
        r[i] = (T)it.next();
    }
    // more elements than expected
		// 如果遍历完成,发现仍未至迭代器的末尾,则调用finishToArray重新分配数组并完成剩余元素的填充
    return it.hasNext() ? finishToArray(r, it) : r;
}

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

可分配的最大数组大小。一些虚拟机在数组中保留一些头字。尝试分配更大的数组可能会导致OutOfMemoryError:请求的数组大小超出虚拟机限制。

9. private static <T> T[] finishToArray(T[] r, Iterator it)

当迭代器返回的元素比预期的多时,在toArray中重新分配正在使用的数组,并完成从迭代器中填充它的操作。

源码如下:

@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);
        }
				// 在数组的i索引位置放置当前遍历到的元素,然后i加1
        r[i++] = (T)it.next();
    }
    // trim if overallocated
		// 如果重新分配后数组长度过长,则进行数组复制以实现trim效果
    return (i == r.length) ? r : Arrays.copyOf(r, i);
}

10. private static int hugeCapacity(int minCapacity)

获取数组的最大容量。

源码如下:

private static int hugeCapacity(int minCapacity) {
		// 负数是不可以的,直接抛出异常
    if (minCapacity < 0) // overflow
        throw new OutOfMemoryError
            ("Required array size too large");
		// 如果最小容量需求大于集合所允许的最大数组容量,则此时取当前虚拟机所支持的Integer最大值
		// 否则就取集合所允许的最大数组容量
    return (minCapacity > MAX_ARRAY_SIZE) ?
        Integer.MAX_VALUE :
        MAX_ARRAY_SIZE;
}

11. public boolean add(E e)

该方法的默认实现为抛出UnsupportedOperationException

源码如下:

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

12. public boolean remove(Object o)

此实现遍历集合以查找指定的元素。如果找到该元素,则使用迭代器的remove方法从集合中删除该元素。

请注意,如果此集合的iterator方法返回的迭代器未实现remove方法并且该集合包含指定的对象,则此实现将引发UnsupportedOperationException

源码如下:

public boolean remove(Object o) {
    Iterator<E> it = iterator();
		// 当指定元素为null时,遍历集合,对每个元素执行 “== null”的判断
		// 否则,使用equals方法判断,找到对应对象后,使用迭代器的remove方法删除
		// 从此实现上看,仅删除第一个命中的元素,删除后即返回true
    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;
}

13. public boolean containsAll(Collection c)

此实现将遍历给定的集合,依次检查每个元素以查看其是否包含在此集合中。如果所有元素都包含,则返回true,否则返回false

源码如下:

public boolean containsAll(Collection<?> c) {
		// 遍历指定集合c,然后调用contains方法判断每一个迭代到的元素是否存在于当前集合中
		// 发现有一个不包含则直接返回false
    for (Object e : c)
        if (!contains(e))
            return false;
    return true;
}

14. public boolean addAll(Collection<? extends E> c)

此实现遍历给定的集合,并将迭代器返回的每个对象依次添加到此集合。

请注意,除非重写add(假定指定的集合为非空),否则此实现将抛出UnsupportedOperationException

源码如下:

public boolean addAll(Collection<? extends E> c) {
    boolean modified = false;
		// 遍历指定的集合c
    for (E e : c)
				// 调用add方法添加元素到当前集合
        if (add(e))
            modified = true;
    return modified;
}

15. public boolean removeAll(Collection c)

此实现遍历当前集合,依次检查迭代器返回的每个元素以查看其是否包含在指定的集合中。如果包含,则使用迭代器的remove方法将其从此集合中删除。

请注意,如果iterator方法返回的迭代器未实现remove方法并且此集合的确包含给定集合的一个或多个元素,则此实现将抛出UnsupportedOperationException

源码如下:

public boolean removeAll(Collection<?> c) {
    Objects.requireNonNull(c);
    boolean modified = false;
    Iterator<?> it = iterator();
		// 遍历当前集合
    while (it.hasNext()) {
				// 使用指定集合的contains方法判断是否包含当前迭代到的元素
        if (c.contains(it.next())) {
						// 如果包含,使用迭代器的remove方法删除
            it.remove();
            modified = true;
        }
    }
    return modified;
}

16. public boolean retainAll(Collection c)

此实现遍历当前集合,依次检查迭代器返回的每个元素以查看其是否包含在指定的集合中。如果没有包含,则使用迭代器的remove方法将其从此集合中删除。

请注意,如果iterator方法返回的迭代器未实现remove方法并且此集合的确包含给定集合中一个或多个不存在的元素,则此实现将抛出UnsupportedOperationException

总体来说,该方法执行后,当前集合中仅剩余当前集合和指定集合中均存在的元素。

源码如下:

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

17. public void clear()

此实现遍历当前集合,并使用Iterator.remove操作删除每个元素。大多数实现可能会选择重写此方法以提高效率。

请注意,如果此集合的iterator方法返回的迭代器未实现remove方法并且该集合非空,则此方法将抛出UnsupportedOperationException

源码如下:

public void clear() {
    Iterator<E> it = iterator();
		// 遍历当前集合,使用迭代器删除每个元素
    while (it.hasNext()) {
        it.next();
        it.remove();
    }
}

18. public String toString()

返回此集合的字符串表示形式。字符串表示形式包括一个集合元素的列表,这些元素按其迭代器返回的顺序排列,并括在方括号([])中。相邻元素由字符,(逗号和空格)分隔。元素通过StringvalueOf(Object obj)方法转换为字符串。

源码如下:

public String toString() {
    Iterator<E> it = iterator();
		// 如果当前集合为空,则返回[]
    if (! it.hasNext())
        return "[]";

		// 使用StringBuilder进行拼接
    StringBuilder sb = new StringBuilder();
    sb.append('[');
    for (;;) {
        E e = it.next();
				// 如果当前元素就是当前集合,则此时使用“(this Collection)”来展示
        sb.append(e == this ? "(this Collection)" : e);
        if (! it.hasNext())
            return sb.append(']').toString();
        sb.append(',').append(' ');
    }
}