bigywater.tech
Java 内部原理 · 74

数组默认值真实验证:char数组的默认值不是'0',是空字符

"数组元素有默认值,局部变量没有"是基础规则,但 char 数组的默认值到底是什么、多维数组只分配外层时内层到底是什么状态,这篇真实跑一遍确认。

char默认值数值是0,不是'0'
真实验证:char[] 的默认值是Unicode空字符\u0000,强转成int后真实是0,不是字符'0'(其数值是48)
未分配内层数组真实是null
真实验证:int[3][] 只分配外层时,partial[0] 真实是null,访问 partial[0][0] 真实抛出NullPointerException

上一篇:浮点数精度真实验证

真实验证:各种基本类型数组的默认值

用 new 创建数组但不赋值,直接打印每种类型的默认元素值。

ArrayDefaultValueDemo.java int[] intArr = new int[3]; boolean[] boolArr = new boolean[3]; double[] doubleArr = new double[3]; char[] charArr = new char[3];
真实实测
int[] 默认值: [0, 0, 0]
boolean[] 默认值: [false, false, false]
double[] 默认值: [0.0, 0.0, 0.0]
char[] 默认值(数字形式): 0(真实是'\u0000'空字符,不是'0')
Object[] 默认值: [null, null, null]

真实结果确认了每种基本类型都有一个真实、确定的零值作为数组元素默认值:数值类型是 0(或 0.0),boolean 是 false,引用类型是 null。char 类型最容易被搞错——它的默认值是 Unicode 空字符 '\u0000',强制转换成 int 后真实是数值 0,不是字符 '0'(字符 '0' 的真实 Unicode 数值是 48)——如果直接打印 char[] 数组,默认值在控制台上通常表现为不可见字符,而不是数字字符串。

真实验证:数组元素默认值 vs 局部变量的强制赋值规则

这是两条完全不同的语言规则,容易被混为一谈。

真实实测
局部变量不会有默认值(编译器强制要求先赋值才能使用),但数组元素会——这是真实的语言规则差异
真实的语言设计取舍。Java 编译器对局部变量有"明确赋值"(definite assignment)的强制要求——一个声明了但没赋值的局部变量,如果被直接使用,真实会编译不通过。但数组元素不受这条规则约束:数组是在运行时(堆上)分配的一块连续内存,JVM 在分配这块内存时会真实把它清零,所以数组元素"天然"就有确定的默认值,不需要、也无法在编译期做类似局部变量那样的"是否已赋值"静态检查。这个差异的本质是:局部变量的赋值状态是编译期可分析的(基于代码的控制流),而数组的长度、内容在很多场景下是运行时才能确定的。

真实验证:多维数组只分配外层时,内层数组真实是 null

Java 的多维数组本质是"数组的数组",如果只分配了外层,内层元素的默认值遵循引用类型规则——是 null,不是自动分配好的空数组。

ArrayDefaultValueDemo.java int[][] partial = new int[3][]; // 只分配外层,内层维度留空 System.out.println(partial[0]); int x = partial[0][0]; // 会怎样?
真实实测
int[3][] 只分配外层,partial[0] 真实是: null
访问未分配的内层数组真实抛出 NullPointerException
int[2][2] 完整分配后 full[0][0] 真实默认值: 0

真实结果印证了"多维数组是数组的数组"这个本质:int[3][] 的元素类型是 int[],这是一个引用类型,所以每个未分配的元素真实默认值就是 null,直接访问 partial[0][0] 真实会像访问任何 null 引用一样抛出 NullPointerException。只有当内层维度也真实被分配(new int[2][2]),内层数组的元素才会按照基本类型规则拿到默认值 0。

分步演示:哪些默认值是"零",哪些是 null

每一行都是真实运行这段代码得到的结果。

char[] 的默认值数值是 0 不是字符 '0'(48);int[3][] 只分配外层时,内层真实是 null 不是空数组
这一步新验证的默认值

    参考与说明

    • 本文全部结果均在本机真实运行 Java 17 得到,各类型默认值重复运行完全一致(这是JVM规范里的确定性行为)。
    • 和自动装箱内存占用那篇一起看,能更完整理解基本类型数组和对象数组在内存布局上的真实差异。
    • 没有涉及:数组默认值清零操作对大数组分配性能的真实影响、Arrays.fill() 和 System.arraycopy() 在覆盖默认值时的真实性能对比——这两个话题留给系列后面按需再写。
    京ICP备2026067502号-1京公网安备11010502063487号