基本类型数组存值,包装类数组存引用;前者元素连续存储且默认初始化,后者元素为null引用且需装箱。关键差异导致==比较、空指针、集合兼容性等行为不同。

Java 中基本类型数组和包装类数组的存储方式差异,核心在于“值 vs 对象”以及“栈 vs 堆”的内存模型。理解清楚这点,就能避免常见陷阱,比如 null 异常、== 比较出错、集合传参失败等。
基本类型数组:值连续存栈(或堆中连续块),无对象开销
声明如 int[] arr = new int[5]; 时:
当用户要求为 Java 代码添加注释、修改注释、审查注释、整理注释格式,或要求按照代码注释规范处理 Java 文件时,使用本技能。本技能用于统一生成和维护 Java 类注释模板、按 Git 对比 release 判断版本号、补充每行代码上方中文块注释、调整注释空行规则,并保持 Java 文件 UTF-8 无 BOM 编码。典型触发场景包括:补充类注释、更新 @version、检查 @author 来源、整理行尾注释、把注释放到代码上一行、检查注释是否符合规范、构建前检查 Java 注释风格。
- 整个数组对象本身在堆中分配,但每个元素直接存的是
int的原始值(如 0、100、-5),不是引用; - 数组内存是连续的一整块,例如 5 个
int占用 5 × 4 = 20 字节; - 元素默认初始化为对应基本类型的零值(
int是 0,boolean是false); - 没有
null元素的概念——每个位置都必然有确定的值。
包装类数组:存的是对象引用,实际对象在堆中分散
声明如 Integer[] arr = new Integer[5]; 时:
- 数组本身在堆中,但每个数组元素存的是 指向 Integer 对象的引用(类似指针),不是值;
- 初始状态下,所有 5 个引用都为
null,不指向任何对象; - 只有显式赋值(如
arr[0] = 100;)才会触发自动装箱,调用Integer.valueOf(100),此时可能复用缓存对象(-128~127),也可能新建对象; - 每个
Integer实例独立存在于堆中(含对象头、字段等),数组只保存它们的地址,所以内存不连续、有额外开销。
关键对比:同一段代码为何行为不同?
看这个例子:
int[] a = {1, 2, 3};
Integer[] b = {1, 2, 3};
System.out.println(a[0] == a[1]); // false(值比较)
System.out.println(b[0] == b[1]); // true(因为 1 和 2 在缓存范围内,引用相同)
System.out.println(b[0].equals(b[1])); // false(内容不同)
-
a数组里是三个独立的int值,==比较数值; -
b数组里是三个引用,==比较的是地址——而Integer.valueOf(1)总返回同一个缓存对象,所以b[0] == b[1]成立(注意:仅限 -128~127); - 一旦超出缓存范围(如
new Integer[1]赋值2000),==就不可靠,必须用equals()。
实际使用建议
- 需要高性能、大量数值计算或内存敏感场景(如图像像素、科学计算),优先用基本类型数组;
- 要放进
List<integer></integer>、Map<integer string></integer>等泛型结构,只能用包装类数组(或逐个装箱); - 对包装类数组做遍历时,务必判空:
if (b[i] != null) { ... },否则拆箱会抛NullPointerException; - 不要用
==比较包装类数组元素的逻辑相等性,统一用.equals()。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










