Menu

Java 数组:声明、初始化、访问与遍历

Java 数组的工作原理:固定长度、声明和初始化、索引、length、遍历、多维数组,以及 Arrays 工具类。

本页包含可运行的编辑器。编辑、运行,立即查看输出。

数组是固定大小的列表

Java 中的数组存放固定数量、同一类型的值,这些值按顺序排列,通过位置访问。“固定”是关键词:数组一旦创建,长度就永远不会改变。“同一类型”也是:int[] 只能存放 int 值,String[] 只能存放字符串。这种死板换来的是数组的速度快、占用内存少。

声明数组类型时,在元素类型后面加上 [],然后赋值一个字面量,或者用 new 分配一个数组:

方括号可以放在类型后面(int[] scores),也可以放在名称后面(int scores[])。两种都能编译,但 int[] scores 才是地道的 Java 风格:把 [] 和类型写在一起,这才是它该在的位置。

用 new 创建数组

当你还不知道具体的值、但知道大小时,就用 new。它会分配这些位置,并用该类型的默认值填充:

这些默认值不是随机的垃圾值,Java 会把每个元素初始化为零值。数值类型从 0(或 0.0)开始,boolean 从 false 开始,String 这样的引用类型从 null 开始。这个 null 值得记住:刚分配的 String[] 里全是 null,对其中任何一个调用方法都会抛出 NullPointerException。

索引从 0 开始

通过索引读写元素,索引从 0 开始计数。最后一个有效索引永远是 length - 1:

和某些脚本语言中的数组不同,越界访问不会悄悄返回 null 或 undefined,而是直接抛出异常。试着读取一个不存在的索引:

这个程序会崩溃,输出:

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 3

这是初学者最常见的错误之一。原因几乎总是循环条件中差了一位:本该用 < 却用了 <=。

length 是字段,不是方法

每个数组都在 length 字段中保存自己的大小。注意:没有括号。

这里有一个每个人都至少会踩一次的坑:数组用 .length(字段),而 String 用 .length()(方法)。对数组写 nums.length() 会导致编译错误,对字符串写 text.length 也一样。同一个词,规则不同:数组的那个没有括号。

遍历数组

上一页你学过 for-each 循环,在不需要索引时,它是读取每个元素最简洁的方式:

当你需要索引时,比如打印位置编号、原地修改元素或者倒序遍历,就使用经典的带索引 for 循环,以 length 作为边界:

条件是 i < names.length,而不是 <=。用 <= 会多走一步,抛出上一节提到的越界异常。一个简单的规则:只读取值时用 for-each,需要位置或要写回数组时用带索引的 for。

多维数组

二维数组其实是数组的数组,可以把它想象成由行和列组成的网格。再加一对方括号即可:

grid[row][column] 选取单个格子。因为每一行都是一个独立的数组,grid.length 是行数,grid[0].length 是第一行的列数。各行的长度甚至可以不同(这叫锯齿数组),不过大多数网格都是矩形的。

Arrays 工具类

数组本身几乎没有方法:你没法直接对它进行有用的排序或打印。为此,Java 提供了 java.util.Arrays 工具类,里面全是专门处理这些事情的静态方法:

这里有几个值得依赖的方法。Arrays.toString(arr) 是打印数组的正确方式,直接打印数组只会得到 [I@1b6d3586 这样没用的字符串。Arrays.sort 原地排序。Arrays.copyOf 就是“调整大小”的方法:它返回一个你指定长度的新数组,多出的位置用默认值填充(上面多出的两个位置是 0)。Arrays.binarySearch 只有在已排序的数组上才能正确工作。

数组与 ArrayList

当大小事先已知且不会改变时,就用普通数组:一组固定的星期几、游戏棋盘、像素数据。数组速度快、开销小,但固定长度确实是个限制:要往长度为 6 的数组里加第七个元素,只能重新建一个全新的数组。

一旦你需要自由地添加和删除元素,数组就不好用了。这正是 ArrayList 的用途:一个可以变长的列表,会替你处理复制工作。

下一步:ArrayList

当你不知道会有多少个元素,或者这个数量在程序运行时会变化,固定长度的数组就会碍事。ArrayList 是 Java 给出的答案:一个按需变长或变短的列表,用 add 和 remove 方法代替手动处理索引。这就是下一页的内容。

常见问题

Java 中如何声明和初始化数组?

用方括号声明类型并赋值一个字面量:int[] nums = {1, 2, 3};。要创建一个固定大小的空数组,使用 new:int[] nums = new int[5];,这样会得到 5 个位置,每个都填充为默认值(int 为 0,对象为 null)。

Java 中如何获取数组的长度?

使用 length 字段(不带括号):nums.length。它是字段而不是方法,所以 nums.length() 会导致编译错误。注意 String 用带括号的 .length(),而数组用不带括号的 .length,这是一个经典的混淆点。

Java 数组创建后可以改变大小吗?

不可以。Java 数组的长度在创建时就固定了,无法变长或变短。如果需要可变长度的列表,改用 ArrayList。要“调整”数组的大小,只能新建一个更大的数组,再把元素复制过去。

Java 中的 ArrayIndexOutOfBoundsException 是什么?

它是访问不存在的索引时出现的运行时错误,即索引小于 0 或 >= array.length。和某些语言不同,Java 对越界访问不会返回默认值或 null,而是直接抛出异常。有效索引始终是从 0 到 length - 1。

Coddy 编程语言插图

和 Coddy 一起学编程

开始