iterator底层是逻辑游标而非真实指针;初始位置在首元素前,next()才取首元素;arraylist用索引、linkedlist用节点引用、hashset/hashmap用桶+链表/树定位;remove()删lastreturned元素;fail-fast依赖modcount与expectedmodcount比对。

Iterator 的底层指针不是真实内存地址意义上的“指针”,而是一个逻辑游标(cursor),用来标记当前遍历位置。它不暴露底层结构,但不同集合的实现方式差异很大——理解这点,就能避开常见误区。
指针初始位置:总在第一个元素之前
调用 collection.iterator() 后,得到的迭代器对象,其内部游标(比如 ArrayList 中的 cursor 字段)初始值为 0,但它指向的是“第一个元素上方的空白处”,不是元素本身。所以第一次调用 hasNext() 实际检查的是索引 0 是否有效;第一次 next() 才真正取 elementData[0] 并把 cursor 推到 1。
不同集合的游标移动方式完全不同
游标怎么动,取决于集合底层结构:
- ArrayList:游标是整数索引(int cursor),next() 直接读 elementData[cursor],然后 cursor++
-
LinkedList:游标是节点引用(Node
next ),next() 返回 next.item,再令 next = next.next - HashSet / HashMap:游标是哈希桶数组的索引 + 当前桶内链表/红黑树节点位置,需跳过空桶、处理冲突链,更复杂但对外完全透明
remove() 删除的是 lastReturned 元素,不是 next 元素
很多人误以为 remove() 删的是下一次 next() 将返回的元素,其实不然:
- 每次成功调用 next(),都会把刚取到的元素记录为 lastReturned(通常是个索引或节点引用)
- remove() 实际删的是这个 lastReturned 对应的元素,并重置状态(如将 lastRet 设为 -1)
- 因此必须先调一次 next(),再调 remove(),否则会抛 IllegalStateException
fail-fast 机制靠的是 modCount 检查
迭代器不是独立副本,而是和原集合共享状态:
- 集合内部维护一个修改计数器 modCount
- 迭代器创建时记录当时的 expectedModCount = modCount
- 每次调用 next() 或 hasNext() 前,都会比对两者是否一致
- 不一致就立即抛 ConcurrentModificationException,这是检测“非迭代器途径修改集合”的安全机制
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











