数组长度存储在对象头后的专用槽中,由JVM自动写入且不可修改,非普通字段,不占实例字段空间,无法通过反射或Unsafe修改,访问时由JVM指令直接读取并校验。

Java数组对象的长度信息确实存储在内存中,但不是作为普通字段暴露给开发者,而是作为数组对象头(Object Header)的一部分,由JVM在创建数组时自动写入并维护。
数组长度是对象头的固有属性
在HotSpot虚拟机中,每个对象(包括数组)的对象头包含两部分:Mark Word和Klass Pointer。对于数组对象,JVM会在对象头之后、元素数据之前额外预留一个4字节(32位JVM)或8字节(64位JVM,开启指针压缩时仍为4字节)的区域,专门用于存储数组长度(array length)。这个长度值在数组创建时一次性写入,之后不可修改——这正是final语义的底层体现,尽管length字段在Java源码中并未显式声明为final。
length字段不占用实例字段空间
Java语言规范规定数组类型没有显式的类定义,因此不存在传统意义上的“实例变量”。array.length不是从某个父类继承而来,也不是通过字段读取实现的。JVM在字节码层面将arraylength指令直接翻译为对对象头后长度槽的内存读取操作,绕过了字段查找流程。这意味着:
- 无法通过反射获取或修改
length字段(getDeclaredFields()返回空数组) - 不能在子类中覆写
length,因为数组根本不是普通类,也没有继承关系 - 使用
Unsafe也无法安全地修改该位置的值——破坏长度会导致后续访问越界或JVM校验失败
与普通对象字段的内存布局对比
以int[] arr = new int[5]为例,在堆中实际布局如下(简化示意,忽略对齐填充):
立即学习“Java免费学习笔记(深入)”;
- 对象头(12字节):Mark Word(8B) + Klass Pointer(4B)
- 长度字段(4B):值为5
- 元素数据区(5 × 4 = 20B):连续存放5个int值
而普通对象如class A { int len; }的实例中,len属于实例字段,位于对象头之后、对齐填充之前,其值可读可写,且受访问控制和继承规则约束。
JVM如何保障length的可靠性
长度信息的安全性不依赖Java层保护,而由JVM在多个环节强制保证:
- 数组创建指令(
newarray、anewarray、multianewarray)在执行时立即写入长度,且只允许一次 - 所有数组访问指令(
iaload,aastore等)在运行时先检查索引是否满足0 ≤ index ,否则抛出<code>ArrayIndexOutOfBoundsException - GC过程会识别数组对象结构,跳过对长度槽的扫描(它不是引用类型),避免误判或污染
这种设计兼顾了性能(零成本抽象)、安全性(不可篡改)和语义清晰性(长度即数组本质属性)。










