abstractcollection是集合实现的模板父类,只需提供iterator()和size()即可获得完整collection行为;它不支持直接实例化,子类必须实现这两个抽象方法或声明为abstract。

AbstractCollection 是集合实现的“脚手架”
它不让你从零写 contains、remove、isEmpty 这些基础方法,而是把 80% 的通用逻辑都封装好了——只要你提供 iterator() 和 size(),就能直接用上全套 Collection 行为。
比如你写一个只读的文件行集合(每行是字符串),不用重复实现 containsAll 或 toArray,继承 AbstractCollection<string></string> 后只重写这两个抽象方法就行:
public class LinesCollection extends AbstractCollection<String> {
private final Path file;
public LinesCollection(Path file) { this.file = file; }
@Override
public Iterator<String> iterator() {
try {
return Files.lines(file).iterator();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public int size() {
try {
return (int) Files.lines(file).count();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
- 注意:这个例子里
size()是 O(n) 的,但AbstractCollection不强制要求高效,只保证语义正确 -
iterator()返回的迭代器如果不可移除(如Files.lines()的流式迭代器),那remove()方法会抛UnsupportedOperationException——这完全合法,因为AbstractCollection默认实现就是靠迭代器的remove()工作的 - 别忘了加无参构造或
Collection构造参数,方便框架反射或泛型推导
为什么不能直接 new AbstractCollection?
因为它是个抽象类,没有实现 iterator() 和 size() ——JVM 在实例化时会直接报 java.lang.InstantiationException。
常见错误现象:
立即学习“Java免费学习笔记(深入)”;
- IDE 提示 “Cannot instantiate the type AbstractCollection”
- 编译通过但运行时报
AbstractCollection is not abstract and does not override abstract method iterator()...(说明你漏了abstract声明)
真正该做的,是把它当“模板父类”用:
- 子类必须声明为
abstract(如果你还不想实现全部抽象方法) - 或者立刻补全
iterator()+size(),否则编译不过 - 不要试图在子类里把
iterator()返回null——contains()等方法会 NPE
哪些方法可以/应该重写?
AbstractCollection 的默认实现全是基于 iterator() 的遍历,所以性能敏感场景下,你大概率要重写:
-
contains(Object o):如果底层数据结构支持哈希或索引查找(比如你包装的是HashSet),就别让它傻乎乎遍历 -
remove(Object o):同理,若能 O(1) 删除,就别走迭代器 remove 循环 -
toArray():默认先按size()分配数组,再逐个填;如果你知道元素类型且可预估大小,重写能省一次扩容 -
isEmpty()通常不用重写——它直接调size() == 0,但如果你的size()很重(比如要扫磁盘),那就该单独优化
不建议重写的有:addAll、retainAll、clear ——它们逻辑清晰、边界明确,且复用度高;自己重写反而容易漏掉 Objects.requireNonNull 或并发安全检查。
和 ArrayList / HashSet 继承关系的实际影响
所有标准集合(ArrayList、LinkedList、TreeSet、LinkedHashSet)其实都间接继承自 AbstractCollection,只是中间隔着 AbstractList、AbstractSet 等层。
这意味着:你写的自定义集合只要继承它,就能无缝接入现有生态 —— 比如传给 Collections.synchronizedCollection()、被 Stream.of(collection) 接收、甚至作为 Spring 的 @Value("${list.of.strings}") 注入目标。
- 兼容性没问题,但要注意:
AbstractCollection没实现Serializable,所以你的子类如果要序列化,得自己加implements Serializable并定义serialVersionUID - 它的
equals()和hashCode()是空实现(继承自Object),所以除非你显式重写,否则两个内容相同的自定义集合不会equals——这点极易忽略
最常被跳过的其实是 toString():默认用 Object.toString() 输出哈希码,调试时一脸懵。加一行 @Override public String toString() { return Arrays.toString(toArray()); } 就能救回大量排查时间。










