java数组长度不可更改,因jvm在分配时锁定连续内存边界并将其长度写入对象头,length为final字段且无resize方法,gc、jit等均依赖其恒定性。

Java 数组长度一旦确定就不可更改,不是语言“不给改”,而是 JVM 在内存层面压根没留这个口子——它从分配那一刻起,就锁死了整块连续内存的边界。
连续内存块决定了长度必须固定
当你写 int[] arr = new int[5];,JVM 就在堆中划出一段**严格连续、恰好 20 字节(5 × 4)** 的空间,并把起始地址和这个“5”一起记进数组对象头里。后续所有 arr[i] 访问,都靠公式“起始地址 + i × 4”直接算出物理位置——这个公式成立的前提,就是元素个数和单元素大小永远不变。
如果允许中途改长度:
- 就得重新找一块更大的连续内存(未必能立刻找到)
- 把全部旧数据复制过去
- 更新所有指向原数组的引用
- 再释放旧内存
这套动作早已超出数组的设计职责,属于 ArrayList 这类封装层该干的事。
length 是 final 字段,编译期就封印了
arr.length 不是普通属性,而是 public final int 类型。JVM 层面保证它自创建起恒定不变,任何试图修改它的行为都会被拦截:
- arr.length = 10; → 编译报错:“Cannot assign a value to final variable 'length'”
- 用反射强行 setAccessible(true) 再赋值 → 运行时抛 IllegalAccessException 或静默失败
- 数组 API 中根本不存在 resize()、setLength() 等方法
它不是“隐藏功能”,而是 JVM 对象模型中不可动摇的身份标识之一。
GC、JIT 和边界检查全靠 length 稳如磐石
垃圾回收器靠 length 精确判断这个数组到底占多少字节,扫到哪儿该停;JIT 编译器基于它做循环展开、消除冗余边界检查;每次 arr[i] 访问前的越界检查,也全依赖这个创建时就定死的值。
若 length 可变:
- GC 可能漏掉部分内存,或错误扫描到其他对象区域
- JIT 优化失效,性能倒退
- 多线程下检查与实际访问之间出现竞态:检查时 i
所谓“扩容”,只是换了引用,不是动了原数组
你写的这行代码:
arr = new int[10];
不是把原来那个长度为 5 的数组“拉长”了,而是:
- 在堆上新建一块 40 字节的新内存
- 让变量 arr 指向它
- 原来的长度 5 的数组还在堆里,等着 GC 回收
原数组对象本身没被碰过,它的 length 字段始终是 5。这种“假扩容”本质是对象替换,不是结构变形。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











