public abstract class AbstractCollection<E> extends Object implements Collection<E>
复制代码
所有的子类:
AbstractList, AbstractQueue, AbstractSet, ArrayDeque, ConcurrentLinkedDeque
文档: 此类提供集合接口的骨骼(框架、概要)实现, 以最小化实现此接口所需的工作量。 为了实现不可修改集合, 程序员只需扩展此类并为 iterator
和size
方法提供实现。(迭代器方法返回的迭代器必须实现 hasNext 和next 方法)。
为了实现可修改的集合, 程序员必须另外重写此 类 add 方法
(否则将引发 UnsupportedOperationException), 迭代器方法返回的迭代器必须另外实现其remove 方法
。
程序员通常应根据集合接口规范中的建议提供void(no argument) 和 collection
构造函数。
此类中的每个非抽象方法的文档详细描述了其实现。如果正在实现的集合承认更有效的实现, 则这些方法中的每一个都可能被重写。
从 java.lang.Object 继承的方法 clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait 从 java.util.Collection 接口继承的方法 equals, hashCode, parallelStream, removeIf, spliterator, stream 从 java.lang.Iterable 继承的方法 forEach
我们看看源码:
public abstract class AbstractCollection<E> implements Collection<E> {
/**
* Sole constructor. (For invocation by subclass constructors, typically
* implicit.)
* 构造方法,用于子类调用,通常是隐式的。我们知道 抽象类可以有自己的构造方法,但是不能被实例化,抽象类的构造
* 方法通常用于子类初始化
*/
protected AbstractCollection() {
}
// 前面我们从文档中知道,如果要实现自己的不可修改的实现类,那么需要实现iterator() 和 size() 方法。
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())
// 这里有一个小技巧,通常我们使用 equals 方法,前面的对象不能为空,否则就NPE了,所以这里首先判断了 o == null
// && 和 || 也有这样的妙用,可以有效的避免一些异常。
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;
}
// 前面文档中说,如果我们要实现自己的可以修改元素的集合类,那么需要实现 add 方法,否则会抛出 UnsupportedOperationException
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 void clear() {
Iterator<E> it = iterator();
while (it.hasNext()) {
it.next();
it.remove();
}
}
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(' ');
}
}
}
复制代码
从代码中我们看到,在 AbstractCollection 抽象类中,完善了大部分常用的方法,具体的方法使用展示,我们在上一篇笔记 Collection 接口中已经展示了。这些常用方法的实现,是子类在继承的时候,只需要实现自己的 add ,size , iterator 以及 iterator 中的 remove 方法,大大的减小了工作量。这也是 抽象类存在的重要意义之一。
另外,add 方法没有定义为抽象类,而且直接在 add 方法中抛出了异常。为什么这么做呢?因为不是每一个集合类都需要 add 方法,抽象类不应该有子类不需要的抽象方法。另外,如果我们要实现可修改的集合,那么我们就必须实现 add 方法,否则,视为集合不可变,就应该在 add 方法中抛出异常。