1. 数组——元素的容器
你多半听说过,计算机可以处理海量信息。条件语句(if-else)和循环(for、while)当然有所帮助。但仅靠它们还不够,因为要处理的数据必须先被存储起来。
为此,在 Java 中(几乎所有编程语言也是如此)都有一种很棒的东西:数组(Array)。它们有时也被称为表。
数组是一种特殊的对象,在其中可以存储的不只是一个值,而是多个值。

如果把变量比作一个盒子(可以存放某个值),那么数组更像是内部被分成多个小格的盒子。在这个“数组盒子”里,每个小格都有自己的编号。编号当然是从 0 开始的……
我们还可以再举个例子:把普通住宅和高层公寓做个比较。普通住宅住一户人家,而高层公寓被分成很多套房。要给住在普通住宅的家庭写信,需要写明住宅的唯一地址;要给住在公寓里的家庭写信,需要写明住宅的唯一地址以及公寓号。
因此,“数组变量”就像“高层公寓”。它可以存放多个值。这个变量里有多套“房间”(单元格),可以通过它们的编号(索引)来访问每一套。
为此,只需要在变量名后面的方括号中写上要访问的单元格索引即可。这相当简单:
array[index] = value;
其中,array 是数组变量名,index 是数组中单元格的编号,value 是我们想写入该单元格的值。
不过先让我们来弄清楚如何创建数组。
2. 在 Java 中创建数组

假设你的程序需要在某处存放100个整数。数组显然很合适。那么该如何创建它呢?
如果只想存放一个整数,可以使用类型 int;而如果要存放100个整数,那么很可能需要一个 int 类型的数组。创建它的代码如下:
int[] array = new int[100];
我们来看看这段代码的含义。
如你所猜,等号左边是一个名为 array、类型为 int[] 的变量声明。在类型 int 后面跟着方括号,这表明这种“盒子”可以存放多个值,而不是一个。
等号右边是“创建对象”(关键字 new)——创建一个包含100个 int 类型元素(单元格)的数组。也并不复杂。
如果我们想创建一个用于存放浮点数、有20 个单元格的数组,创建代码大致如下:
double[] vals = new double[20];
数组中单元格的个数被称为数组的大小或数组的长度。因为能存放许多值,数组也常被称为容器。
重要提示:数组容器的大小在创建之后无法更改。
你可以创建一个新的数组,但已创建的容器长度是无法改变的。
3. 操作数组的单元格
好,创建数组我们已经会了,那如何正确地使用它们呢?
基本上和普通变量一样,只是每次在数组变量名之后必须注明要操作的单元格编号。
数组单元格的编号(索引)总是从 0 开始。如果数组有10个元素,那么它的单元格编号(索引)是0..9;如果数组有200个元素,那么是0..199。以此类推。
示例:
int[] a = new int[10]; // 创建一个包含 10 个 int 元素的数组。
a[2] = 4; // 将值 4 写入索引为 2 的单元格。
a[7] = 9; // 将值 9 写入索引为 7 的单元格。
a[9] = a[2] + a[5]; // 将单元格 2
// (为 4)和单元格 5(为 0)中存储的值的和写入索引为 9 的单元格。
执行上述代码后,内存中将保存如下内容:

数组左侧的灰色列是单元格的编号(索引)。单元格中存放的值为:4、9 和 4。数组创建之后,所有单元格都会被初始化为 0。
重要。数组中所有单元格的数据类型都相同。如果我们创建的是 String 字符串数组,那么其中只能存放字符串。数组的数据类型在创建时指定,之后既不能更改数据类型,也不能更改数组长度。
4. 数组与内存
前面示意图有些许简化。
创建数组(和创建字符串)时,内存中会分配两个块:一个用于存放数组(容器)本体,另一个是存放它在内存中地址的变量。下面的图展示了更准确的情况:

绿色部分表示一个包含10个 int 元素的数组,以及一个 int[] 类型的变量,它在内存中保存着该 int 数组的地址(引用)。
作为对比,蓝色部分是一个普通的 int 变量,存放着值 199。
这和字符串在内存中的存放方式有些类似,不是吗?
没错。就像处理字符串那样,“数组类型的变量”也可以彼此赋值:
int[] a = new int[10]; // 创建一个包含 10 个 int 元素的数组。
a[2] = 4; // 将值 4 写入索引为 2 的单元格。
a[7] = 9; // 将值 9 写入索引为 7 的单元格。
int[] b = a; // 将变量 a 中的地址保存到变量 b。
// 现在 a 和 b 都指向内存中的同一个数组对象。
a[9] = b[2] + a[7]; // 将数组对象索引为 9 的单元格设为以下两者之和,
// 单元格 2(为 4)和单元格 7(为 9)中存储的值。
此时数组对象仍然留在原处,而变量 a 和 b 都保存着指向同一对象的相同地址(引用)。请看示意图:

5. 更详细地使用数组
数组可以由任何类型创建。只需在类型名后面加上方括号即可。创建数组的一般形式如下:
type[] name = new type[count];
其中,type 是我们要在数组中存放的元素(单元格)的类型;Imya 是变量名,我们将通过它来访问数组;count 是数组中的单元格数量。
上面的示例展示了“数组变量的创建”和“数组对象的创建”的规范写法。实际上,这是两件相互独立的事。你也可以分别创建数组变量和数组对象:
type[] name;
name = new type[count];
还有一个很重要的点
数组的索引以及数组的元素个数都可以是变量,甚至是完整的表达式。
示例:
int n = 100;
int[] a = new int[n]; // 创建一个包含 n 个元素的数组
int n = 100;
int[] a = new int[n * 2 + 3]; // 创建一个包含 203 个元素的数组
int n = 100;
int[] a = new int[n];
a[n-1] = 2; // a[99] = 2;
a[n-2] = 3; // a[98] = 3;
a[n/5] = a[n-1] + a[n-2] // a[20] = a[99] + a[98];
数组越界
需要特别注意的是,如果尝试通过一个不存在于数组中的索引访问单元格(在我们的例子中,除 0..99 之外的所有整数),程序会因抛出 ArrayIndexOutOfBoundsException 而异常终止——即“索引超出数组边界”。
6. 数组的长度
如前面的例子所示,我们可以单独创建一个数组类型的变量,并在代码的某处给它赋值(数组对象的引用)。甚至可以这样写:
int[] array; // 创建一个 int[] 类型的数组变量
if (a < 10) // 如果变量 a 小于 10,
array = new int[10]; // 则创建一个包含 10 个元素的数组。
else // 否则
array = new int[20]; // 创建一个包含 20 个元素的数组
那么之后如何与这个数组交互?如何知道它包含多少个元素?
为此,数组提供了一个特殊的属性(变量)——length。我们可以通过如下表达式获取数组的长度:
array.length;
其中,array 是数组变量名,length 是数组对象的属性名。length 的值不可更改:你可以把 length 的值赋给其他变量,但不能给它本身赋值(否则程序将无法通过编译)。
我们可以这样延续上面的例子:
int[] array; // 创建一个 int[] 类型的数组变量
if (a < 10) // 如果变量 a 小于 10,
array = new int[10]; // 则创建一个包含 10 个元素的数组。
else // 否则
array = new int[20]; // 创建一个包含 20 个元素的数组
for (int i = 0; i < array.length; i++) // 遍历数组的所有元素:从 0 到 array.length — 1
{
System.out.println(array[i]);
}
7. Java 数组要点
我们来总结一下关于数组的已知事实:
- 事实 1。 数组由许多单元格组成。
- 事实 2。 访问某个具体单元格需要指定它的编号(索引)。
- 事实 3。 所有单元格类型相同。
- 事实 4。 所有单元格的初始值为 0;如果单元格中存放的是地址,则为 null;对于类型 boolean,初始值为 false。
- 事实 5。 String[] list 只是一个变量声明:容器(数组对象)本身尚未创建。要能够使用它,需要先创建数组(容器)并把它赋给该变量,然后才能使用。见下例。
- 事实 6。 当我们创建数组对象(容器)时,必须指定它的长度——即包含多少个单元格。语法形式为:new TypeName[n]。
- 事实 7。 可以通过属性 .length 获取数组的长度。
- 事实 8。 数组创建之后,既不能更改其元素的类型,也不能更改元素的数量。
String s; // s 为 null
String[] list; // list 为 null
list = new String[10]; // 变量 list 保存着指向一个对象(包含 10 个元素的字符串数组)的引用。
int n = list.length; // n 等于 10
list = new String[0]; // 现在 list 包含一个长度为 0 的数组。
// 数组是存在的,但无法存放任何元素。
list = null;
System.out.println(list[1]); // 将会抛出运行时错误——程序将异常终止。
// list 保存的是空引用——null
list = new String[10];
System.out.println(list[10]); // 将会抛出错误——数组越界。
// 如果 list 包含 10 个元素/单元格,那么允许的索引是:0 1 2 3 4 5 6 7 8 9 —— 共 10 个。
GO TO FULL VERSION