
本文通过一段典型java代码演示arraylist的remove操作如何改变元素索引,进而影响对象的可达性状态;明确说明即使局部变量被置为null,只要对象仍被集合引用,就仍为强可达、不会被垃圾回收。
本文通过一段典型java代码演示arraylist的remove操作如何改变元素索引,进而影响对象的可达性状态;明确说明即使局部变量被置为null,只要对象仍被集合引用,就仍为强可达、不会被垃圾回收。
在Java内存模型中,一个对象是否“可达”(reachable)直接决定其能否被垃圾回收器回收。根据JVM规范,只有当对象无法通过任何强引用链从GC Roots(如线程栈帧中的局部变量、静态字段、本地方法栈等)访问时,才被视为不可达。关键在于:可达性取决于运行时实际的引用关系,而非变量名是否存在或是否曾被赋值为null。
我们来逐行分析原代码中ArrayList
01: var rl = new ArrayList<repairable>(); // rl = [] 02: var car = new Car(); // car 引用 Car 实例 03: var clutch = car.getClutch(); // clutch 引用 Car内部Clutch实例(假设getClutch()返回新实例或内部引用) 04: var engine = (Repairable) null; // engine == null,不构成引用 05: rl.add(car); // rl = [car] 06: rl.add(clutch); // rl = [car, clutch] 07: car = null; // 局部变量car断开,但rl[0]仍强引用Car对象 08: clutch = null; // 局部变量clutch断开,但rl[1]仍强引用Clutch对象 09: rl.add(engine); // rl = [car, clutch, null] → 注意:null是值,不是引用,不指向任何对象 10: rl.set(2, engine); // 仍是rl[2] = null,无实质变化 11: rl.remove(0); // 移除索引0(即car),后续元素左移 → rl = [clutch, null] 12: rl.remove(1); // 移除当前索引1(即null),剩余 → rl = [clutch]</repairable>
⚠️ 关键点在于 ArrayList.remove(int index) 的行为:它删除指定索引处的元素,并将该索引之后的所有元素向左平移一位。因此:
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
- 行11后,原rl[1](clutch)变为rl[0],原rl[2](null)变为rl[1];
- 行12删除的是此时的rl[1](即null),而非原始的clutch;
- 最终rl仅含一个元素:clutch对象的引用。
这意味着:
✅ Clutch实例仍被rl[0]强引用 → 可达;
✅ 若Clutch对象内部持有对Car的引用(例如作为内部类实例或显式保存this.car),且Car未被其他路径隔离,则Car也可能保持可达;
❌ engine始终为null,不构成任何引用,相关对象(如有)不受此列表影响。
? 补充说明:
- null本身不是对象,向ArrayList添加null只是存入一个空引用值,不延长任何对象生命周期;
- 局部变量置null(如第7、8行)仅解除该变量的引用,不影响其他强引用(如集合中的条目);
- 可达性判断必须基于运行时堆中实际存在的强引用链,而非源码中变量的声明或历史赋值。
综上,该代码执行完毕后,Clutch对象(及其可能隐式关联的Car)仍为强可达,不会被垃圾回收。理解ArrayList等动态集合的索引偏移机制,是准确判断Java对象生命周期的关键一环。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










