AbstractCollection 是 JDK 内部用的模板类,仅强制实现 iterator() 和 size(),其余方法如 contains()、remove()、toArray() 等均基于遍历默认实现,性能差且易出错;自定义集合应优先继承 AbstractList/AbstractSet 等语义化骨架类。

AbstractCollection 是什么,为什么你几乎不用直接继承它
它不是让你拿来“扩展出新集合”的首选工具,而是 JDK 内部实现 ArrayList、LinkedList、HashSet 等集合时用的“省事模板”。它的核心价值在于把 Collection 接口里 10 多个方法中能靠 iterator() 和 size() 推导出来的部分,一次性写好——比如 isEmpty()、contains()、remove()、toArray()。
如果你真要自己写一个集合类,优先考虑:
– 继承 AbstractList/AbstractSet/AbstractQueue(它们已按语义预设了行为)
– 或者直接实现 Collection,只重写真正需要定制的部分
– 直接继承 AbstractCollection 容易漏掉关键契约,比如没重写 iterator() 就会抛 UnsupportedOperationException
哪些方法被 AbstractCollection 默认实现了
它只强制你实现两个方法:iterator() 和 size();其余都带默认逻辑,但代价是性能可能很差——所有基于遍历的操作都依赖 iterator() 走一遍。
-
contains(Object o):调iterator()遍历比对,时间复杂度 O(n),别指望它有哈希加速 -
remove(Object o):同样遍历找匹配项再调Iterator.remove(),失败就返回false -
toArray():先用size()分配数组,再遍历填充;若集合大小在迭代中变化,可能抛ConcurrentModificationException -
isEmpty():直接 returnsize() == 0,安全且高效
继承 AbstractCollection 时最容易踩的坑
表面看只要补两个方法就能跑,实际运行时一堆隐性雷:
- 没重写
add(E e)却调用它 → 抛UnsupportedOperationException(父类默认实现就是这么写的) -
iterator()返回的Iterator不支持remove()→ 调remove(Object)会抛异常,而不是静默失败 -
size()返回值和实际元素数不一致 →isEmpty()、toArray()行为错乱,且不会报错,难调试 - 子类没声明
public构造器 → 反射或某些框架(如 Jackson)实例化失败,报NoClassDefFoundError或初始化异常
什么时候真该用 AbstractCollection
极少数场景下它比从零实现更合适:你要封装一个只读、不可变、底层数据源固定(比如静态数组或枚举集合),且不想重复写一堆遍历逻辑。
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
例如封装一个固定字符串集合:
class FixedStringCollection extends AbstractCollection<string> {
private final String[] data = {"a", "b", "c"};
public int size() { return data.length; }
public Iterator<string> iterator() {
return Arrays.stream(data).iterator();
}
// add/remove 等保持默认 UnsupportedOperationException
}</string></string>
注意:Arrays.stream(...).iterator() 返回的是非 fail-fast 迭代器,如果后续要支持并发修改检测,就得自己实现 Iterator 并维护 modCount。
骨架类的意义不在“帮你少写代码”,而在统一行为边界——一旦你偏离了 iterator() + size() 这两个支点,整个默认逻辑就不可信了。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










