首页 / Java 入门教程 / 数组定义与初始化

Java 入门教程

数组定义与初始化

本教程共 100 篇 · 第 24 篇 · 更新于 2026-08-05 · 约 6 分钟阅读

JavaJava 入门教程数组数组初始化默认值

24. 数组定义与初始化

本节目标:学会声明数组、用静态和动态两种方式初始化,记住数组创建后每个位置都有默认值,下标从 0 开始且不能越界。

变量一次只能装一个值。要存 100 个成绩,难道声明 100 个变量?当然不。数组就是”一连串相同类型元素的容器”,用一个数就能管理一批数据。它是 Java 里最基础、也最常用的数据结构。

声明数组

数组类型写法是在元素类型后加一对中括号 []

int[] scores;          // 推荐:int 数组
int nums[];            // 也能写,但不推荐放变量名后
```bash

Java 里中括号跟类型走更清楚,所以第一种写法更常用。光声明还没分配空间,scores 只是个"还没指向任何数组"的引用。真正的内存空间要等 `new` 才出现。

> [!NOTE]
> 推荐 `类型[] 变量名` 的写法,这样类型一目了然。`int[] scores, nums;` 一次声明两个 int 数组。如果写成 `int scores[], nums;`,nums 就变成普通 int 变量了,这种坑很容易踩。

## 静态初始化:一边创建一边给值

如果你已经知道要放哪些数,直接把值列出来:

```java
int[] scores = {88, 92, 75, 60};            // 简化写法
int[] scores2 = new int[]{88, 92, 75, 60}; // 完整写法,可单独成句

花括号里写几个元素,数组长度就是几。第二种 new int[]{...} 写法在方法传参、返回值里很常用,因为它能单独成句,不依附于声明。

Note

new int[]{...} 不能在中括号里再写长度,长度由元素个数决定。写了值又写长度会编译报错,编译器不知道听谁的。比如 new int[3]{1,2,3} 是错的。

动态初始化:先定长度,再填值

有时长度知道,但值要后面算。先给定长度,Java 会自动给每个位置填默认值:

int[] nums = new int[5];   // 长度 5,每个元素默认 0
nums[0] = 10;              // 通过下标赋值
nums[1] = 20;
```bash

`new int[5]` 一口气开出 5 个连续的格子,初始全是 0。之后用 `nums[下标]` 往指定位置放值。动态初始化适合"先占位、后填充"的场景,比如先开好容纳 100 个用户输入的数组。

## 默认值规则

数组创建时没手动赋值的位置,会按类型自动填:

- 整数类型(byte/short/int/long):0
- 浮点(float/double):0.0
- 字符(char):'\u0000'(空字符)
- 布尔(boolean):false
- 引用类型(String、对象等):null

```java
boolean[] flags = new boolean[3];
System.out.println(flags[0]);   // 打印 false

String[] names = new String[2];
System.out.println(names[0]);   // 打印 null

这个默认值机制很贴心:你不用挨个初始化,数组一建好就处在确定的”零值”状态,不会出现随机垃圾数据。

Warning

引用类型数组的元素默认是 null。如果直接调用 names[0].length(),会抛 NullPointerException。使用前要先给每个元素赋值,或者判空。

下标从 0 开始

数组第一个元素下标是 0,不是 1。长度为 n 的数组,合法下标是 0 到 n-1。这是很多语言(包括 C、Java)的约定,源于”下标表示距离起点的偏移量”。

int[] a = {10, 20, 30};
System.out.println(a[0]);   // 10,第一个
System.out.println(a[2]);   // 30,最后一个
```bash

> [!WARNING]
> 下标写成 a.length(即 3)会抛 `ArrayIndexOutOfBoundsException`。访问前想清楚:下标范围是 0 到 长度-1。遍历时用 `i < a.length` 而不是 `<=`。

## 数组长度与不可变

数组一旦创建,长度就固定了,不能伸长缩短。`a.length` 是只读属性,告诉你有多少格。

```java
System.out.println(a.length);   // 3

想装更多数,只能新建一个更大的数组再把旧数据搬过去(或者直接用后面集合章节的 ArrayList,它能自动扩容)。记住:数组是定长的,这是它和 ArrayList 最本质的区别。

数组是一种引用类型

和基本类型不同,数组是引用类型。数组变量本身存的是”指向数组的地址”,不是数组内容。

int[] a = {1, 2, 3};
int[] b = a;        // b 指向同一个数组
b[0] = 99;
System.out.println(a[0]);   // 99,a 也被改了
```bash

两个变量指向同一个数组,改一个另一个也受影响。想复制一份独立的新数组,用 `Arrays.copyOf` 或 `System.arraycopy`,这在第 27 章会讲到。

## Java 25 LTS 与老写法对照

Java 25 推荐写数组的方式和早期版本完全一致,没有语法变化。但老程序员可能习惯一些不太直观的写法,这里点出来:

| 写法 | 状态 | 说明 |
|------|------|------|
| `int[] arr` | ✅ 推荐 | 中括号跟类型,一目了然 |
| `int arr[]` | ⚠️ 不推荐 | 能跑,但声明多个变量时容易出错 |
| `new int[]{1,2,3}` | ✅ 推荐 | 完整写法,可单独成句 |
| `new int[3]{1,2,3}` | ❌ 错误 | 写了长度又写元素,编译报错 |

## 数组的适用场景

什么时候用数组?当你面对"一批同类型、数量确定"的数据时:

- 存储固定数量的配置项
- 处理固定大小的矩阵或表格
- 性能敏感场景(数组比集合更轻量)
- 与底层 API 交互(很多方法参数是数组)
- 实现算法(排序、查找、动态规划表)

如果数量会变,或者要频繁增删,ArrayList 更合适。数组是"死板但高效",ArrayList 是"灵活但有开销"

## 数组与基本类型、引用类型的关系

Java 有 8 种基本类型(intdouble 等)。数组可以是基本类型数组,也可以是引用类型数组:

| 数组类型 | 默认值 | 示例 |
|----------|--------|------|
| `int[]` | 0 | `new int[5]` 全是 0 |
| `double[]` | 0.0 | `new double[3]` 全是 0.0 |
| `boolean[]` | false | `new boolean[2]` 全是 false |
| `String[]` | null | `new String[2]` 全是 null |
| `Object[]` | null | `new Object[2]` 全是 null |

基本类型数组直接存值,引用类型数组存引用(地址)。`int[]` 的每个格子直接放一个 int 数值;`String[]` 的每个格子放一个"指向 String 对象的地址"

## 数组初始化常见错误

初学者在数组初始化上容易栽这些坑:

```java
// 错 1:声明时写长度
// int[5] arr;  编译报错

// 错 2:静态初始化写长度
// int[] arr = new int[3]{1,2,3};  编译报错

// 错 3:越界访问
int[] arr = {1, 2, 3};
// arr[3] = 4;  运行时抛 ArrayIndexOutOfBoundsException

// 错 4:忘了 new 就用
// int[] arr;
// arr[0] = 1;  编译报错:变量 arr 未初始化

养成习惯:声明后先 new,再赋值。静态初始化把声明和赋值合并成一步,是最简洁的写法。

速查表

操作写法说明
声明int[] arr;中括号跟在类型后
静态初始化int[] arr = {1,2,3};长度由元素数决定
完整静态new int[]{1,2,3}可单独成句
动态初始化new int[5]每个位置取默认值
访问元素arr[0]下标从 0 开始
取长度arr.length只读属性,不是方法
越界异常ArrayIndexOutOfBoundsException下标不在 0~len-1
复制数组Arrays.copyOf(arr, n)深拷贝一份
数组判空arr == null || arr.length == 0空引用和空数组都要防

常见疑问

Q:数组声明时可以写长度吗? 不能。int[5] arr; 是错的。长度只在 new 时指定,或由静态初始化元素个数决定。

Q:int[] arrint arr[] 有什么区别? 语义上没有区别。但推荐第一种,因为类型更清晰。特别是声明多个变量时,int[] a, b 两个都是数组,而 int a[], b 只有 a 是数组。

Q:数组可以存不同类型的数据吗? 普通数组不行,必须同一类型。Object[] 可以存任何对象,因为所有类都继承 Object,但取出来时要强转,不如后面讲的泛型集合安全。

Q:int[] arr = new int[5]int[] arr = {1,2,3,4,5} 哪个更好? 看场景。已知具体值用静态初始化(代码更简洁),只知道长度用动态初始化。性能上没有差别。