![Java无难事:详解Java编程核心思想与技术(第2版)](https://wfqqreader-1252317822.image.myqcloud.com/cover/851/47548851/b_47548851.jpg)
2.8 数组
数组是一种数据结构,用来存储同一类型的数据。在内存布局上,数组是一系列连续排列的数据,因此访问速度很快。
数组中的元素是通过一个整型的下标来访问的,代表该元素在数组中的索引位置,数组的索引是从0开始的。
2.8.1 数组类型与声明数组
1.数组类型
在Java中,数组是一种特殊的类型,被称为数组类型(Array Type)。若声明一个数组类型的变量则使用其元素类型后接[],加上数组的名字。例如,声明一个int类型的数组arr,则可以写为:
![](https://epubservercos.yuewen.com/2C78EE/26947315207549306/epubprivate/OEBPS/Images/44554_70_4.jpg?sign=1739397883-MJaMBGZ3pZVp6yadaguVjgxiEN7yDRrP-0-e8ad4fc9e209e6ac1504ffea9b61d402)
在main方法的定义中“public static void main(String[] args)”,args参数的类型就是String数组。
2.声明数组
在C++语言中,我们习惯使用“int arr[3];”这种方式在声明一个数组的同时指定数组的容量,不过在Java中,这行不通,Java中数组变量的声明和数组容量的分配(即数组对象的创建)是分开进行的。
![](https://epubservercos.yuewen.com/2C78EE/26947315207549306/epubprivate/OEBPS/Images/44554_71_1.jpg?sign=1739397883-tSRvmkLvHOvBEIqQ8tL4lPWuh4b7FCG1-0-269bfbd280e30ee22034091c87251036)
上述声明一个int类型的数组变量的四种方式都是合法的,第二种方式是我们推荐的方式,因为它将数组类型(int[])和变量名(num)清晰地区分开了。
2.8.2 创建数组
在声明一个数组之后,就可以为这个数组分配内存空间了,可以看下面的代码。
![](https://epubservercos.yuewen.com/2C78EE/26947315207549306/epubprivate/OEBPS/Images/44554_71_2.jpg?sign=1739397883-FScC1FwCaRd9tsDjlGyOSCERTxU2LjPn-0-ae98b69494211ba95f57955e497f99b1)
第二行代码,我们使用new运算符来创建一个包含3个int类型元素的数组。第三行代码只不过是把前两行代码写在了一行当中。在Java中,new运算符是用来分配内存的,数组的存储需要内存,对象的存储也需要内存,所以当创建一个数组或对象时,我们需要使用new运算符。
![](https://epubservercos.yuewen.com/2C78EE/26947315207549306/epubprivate/OEBPS/Images/44554_71_3.jpg?sign=1739397883-5UsDXjIQNvFu6ocRLTA8cbvVWnTCyza8-0-287536623f51535f5ba51a6b4f24d5ea)
上面的代码是给num数组的三个元素进行赋值的,使用访问运算符([])来访问数组的元素,在中括号([])中的数值叫作数组的下标,也就是第几个元素。需要注意的是,数组第一个元素的下标为0。如果一个数组的大小为n,那么数组的下标范围是0~n-1。
不过我们也可以在声明数组的同时给数组分配初始值,看下面的代码。
![](https://epubservercos.yuewen.com/2C78EE/26947315207549306/epubprivate/OEBPS/Images/44554_71_4.jpg?sign=1739397883-JfC6vr6tN4afFAdEHb87GXrmiV3EIKGw-0-f7fc687b5e6136728a6cd5a86d28c90c)
这行代码定义了一个包含3个int类型元素的数组,并且这3个元素的值依次为:11、22、33。要注意的是,这种写法必须在同一行,如果把上面代码分成两行书写则会出现编译问题。
![](https://epubservercos.yuewen.com/2C78EE/26947315207549306/epubprivate/OEBPS/Images/44554_71_5.jpg?sign=1739397883-sT9sp3m8CWb7Bnm9nNZXPq4JqtYVewaO-0-02381788b39514391bf3e2e96cd117ba)
给数组分配初始值还有一种写法:
![](https://epubservercos.yuewen.com/2C78EE/26947315207549306/epubprivate/OEBPS/Images/44554_71_6.jpg?sign=1739397883-fkXJ1hRfolxyY8U3Y4AllyQFjgHSQuBW-0-f46ac6ac818963eff2a7e4286ba82f30)
不过,在使用这种写法时,要注意不要写成下面的形式了:
![](https://epubservercos.yuewen.com/2C78EE/26947315207549306/epubprivate/OEBPS/Images/44554_72_1.jpg?sign=1739397883-3UEhkLBgaZYoAfUXFZAews5650g6gFO7-0-0dd9d9c8f9636299bd7ef0c2029d37e0)
我们的想法是声明一个包含3个int类型元素的数组,并赋初始值,但不幸的是,这种写法编译器会报错。
2.8.3 使用数组
在声明数组变量并创建数组后就可以通过数组名来使用数组了。数组的使用无非是给指定元素赋值或者获取指定元素的值。前面我们已经了解到,可以使用访问运算符来给数组的元素赋值,同样,使用访问运算符可以获取指定下标元素的值。
我们看代码2.25。
代码2.25 ArrayUse.java
![](https://epubservercos.yuewen.com/2C78EE/26947315207549306/epubprivate/OEBPS/Images/44554_72_2.jpg?sign=1739397883-Up5JRTz1hBcgCacLCm5GBW0BOD0y8QrJ-0-12f3d3e17c3db756e39c3dfc5ff13a20)
程序运行结果为:
![](https://epubservercos.yuewen.com/2C78EE/26947315207549306/epubprivate/OEBPS/Images/44554_72_3.jpg?sign=1739397883-ouJ1tCQ6KP6oCEEk5qK3QsHg3vTt82Kq-0-e0f66d37e4e6fba4bd2a1766cb2d428a)
这段程序很简单,通过for循环依次获取数组中的元素并输出到控制台窗口中。这里我们知道数组的元素个数是3,因此循环条件设置为i<3,假如我们不知道数组中元素的个数怎么办呢?Java中的数组都有一个默认的length属性,该属性的值就是数组中元素的个数,在数组变量上可以使用点号(.)运算符来访问length属性。
我们看代码2.26。
代码2.26 ArrayUse.java
![](https://epubservercos.yuewen.com/2C78EE/26947315207549306/epubprivate/OEBPS/Images/44554_72_4.jpg?sign=1739397883-KZqZKVVDkygU9iy76D4UqFpDTA7g5geF-0-ef16ae2586ebd34299e6684e21e1c44c)
如果只是遍历访问数组中的元素,那么使用“for each”循环会让你的代码更加简洁,如代码2.27所示。
代码2.27 ArrayUse.java
![](https://epubservercos.yuewen.com/2C78EE/26947315207549306/epubprivate/OEBPS/Images/44554_72_5.jpg?sign=1739397883-7vzur4oDdeWAmPMoFi4oCvyZkxsYS8hH-0-14bd1f262e49be5b7594aac2a3651da8)
![](https://epubservercos.yuewen.com/2C78EE/26947315207549306/epubprivate/OEBPS/Images/44554_73_1.jpg?sign=1739397883-mH4gVtojUiqnDnY6FzVN0kk7KnkfB8xJ-0-11e70eb3d890a9119d6c57f4bc4e0542)
2.8.4 匿名数组
在上面的例子中,创建的数组都是保存在一个数组变量中的。有时,在调用方法时,需要传入一个数组类型的参数,为了方便,我们会在传参时直接创建一个数组,而不是把数组保存到一个变量中再传递,如代码2.28所示。
代码2.28 UnnamedArray.java
![](https://epubservercos.yuewen.com/2C78EE/26947315207549306/epubprivate/OEBPS/Images/44554_73_2.jpg?sign=1739397883-8zEpcU6jOqUevIGEdtwv1F3z9fglSpGU-0-729191d11fe14f1a05f36973f8eda5ed)
在第三行代码中,我们直接用new运算符创建了一个包含3个int类型元素的数组,并设定初始值为:1、2、3。然后,把这个数组直接传入UnnamedArray类的method方法。以这种方式创建的数组我们就称之为匿名数组。
当使用匿名数组时,需要注意以下两点:
(1)一定要使用new运算符为数组分配空间并进行初始化。
(2)要使用“new int[]{11,22,33}”这种方式来创建并初始化数组,如果使用“{11,22,33}”方式来创建并初始化数组,则会产生编译错误。
2.8.5 多维数组
下面以二维数组为例。
1.声明二维数组
现在我们已经知道,声明一个一维数组是在类型名称后面加上一对方括号,那么声明二维数组就是在类型名称后面加上两对方括号。
![](https://epubservercos.yuewen.com/2C78EE/26947315207549306/epubprivate/OEBPS/Images/44554_73_3.jpg?sign=1739397883-rd6zkgDLoYt5Yq56YMDe1gn6bPQAQHxn-0-c17f8257dd8439ce93aaa2211b53669b)
上面两行代码都是声明一个二维数组。同样,我们推荐采用第一种声明方式。
2.创建二维数组
创建二维数组也使用new关键字,并在两对方括号中指定二维数组的最大行数和最大列数。
![](https://epubservercos.yuewen.com/2C78EE/26947315207549306/epubprivate/OEBPS/Images/44554_74_1.jpg?sign=1739397883-5mlELxVUKz9ykJvRLvKrBLnqRLbzBcHg-0-4d1793ea9a49d625c765b6802aab355c)
上面的代码创建了两个二维数组,它们的大小都是3行3列。在数学中,我们称之为矩阵。
Java的二维数组还有一个特性,就是它可以针对各个行来创建包含不同列数的二维数组(不规则数组)。
![](https://epubservercos.yuewen.com/2C78EE/26947315207549306/epubprivate/OEBPS/Images/44554_74_2.jpg?sign=1739397883-cUcHOkFNqeP4Rc1wIwoc5DHeISzlbVXK-0-ca881c99f170ab6bde13eb3fc41fe598)
不过,列数不同的数组创建起来比较麻烦。
![](https://epubservercos.yuewen.com/2C78EE/26947315207549306/epubprivate/OEBPS/Images/44554_74_3.jpg?sign=1739397883-T2WnaYrukGI5KHPTZdSqcUzaoiEdb4ss-0-c1ce41f6c882012ed21bcde34c666211)
提示:Java中的二维数组可以看成一个保存一维数组的一维数组。
3.初始化二维数组
初始化二维数组可以用访问运算符([])给每个元素赋值,也可以在二维数组声明时直接创建数组并赋初始值。
![](https://epubservercos.yuewen.com/2C78EE/26947315207549306/epubprivate/OEBPS/Images/44554_74_4.jpg?sign=1739397883-cnOeYt6F1Q2kxl6uUBX0SNmttaKR5NRR-0-57449c44e8b0e4b37acdfe32d3227a5d)
我们在声明二维数组变量num的同时创建了一个3行2列的数组,并给数组分配了初始值。同样,我们也可以使用这种方法创建一个不规则的二维数组。
![](https://epubservercos.yuewen.com/2C78EE/26947315207549306/epubprivate/OEBPS/Images/44554_74_5.jpg?sign=1739397883-SkBoEUMrB7VSA3C4inpevTmuVHk0BtUx-0-1b50176b25ad58560119a36f77f8d826)
4.使用二维数组
与一维数组相同的是,使用访问运算符([])和下标来访问二维数组中的指定元素,如代码2.29所示。
代码2.29 MDArray.java
![](https://epubservercos.yuewen.com/2C78EE/26947315207549306/epubprivate/OEBPS/Images/44554_74_6.jpg?sign=1739397883-zxtgW8Cg3WsQz7GJg8kWvw31l4n81asL-0-55edd7988869d830777197255fbc8a1d)
![](https://epubservercos.yuewen.com/2C78EE/26947315207549306/epubprivate/OEBPS/Images/44554_75_1.jpg?sign=1739397883-IcchP9rpLAQKHiZ3Ukno9IKEKQowIyTr-0-de03a89b955f0b9e85e452b8adfe23e2)
程序的运行结果为:
![](https://epubservercos.yuewen.com/2C78EE/26947315207549306/epubprivate/OEBPS/Images/44554_75_2.jpg?sign=1739397883-ZIpQNibKujYBjVwZraoLZir7ibTYGSGE-0-14beb7ebf960bf0ef572f4c5a1d14eb3)
在访问一维数组的例子中,我们体会到了使用“for each”循环的优势。在使用“for each”循环遍历二维数组时,我们需要使用嵌套循环,外层循环遍历二维数组的行,内层循环遍历二维数组的列。在外层“for each”循环中,我们要注意行元素的类型是“int[]”。
2.8.6 数组的初始值和越界
若我们不为数组赋初始值,而直接访问数组中的元素,那么会出现什么情况呢?
![](https://epubservercos.yuewen.com/2C78EE/26947315207549306/epubprivate/OEBPS/Images/44554_75_3.jpg?sign=1739397883-PnIawMUKW1aUw8ac4JDHz7VMPunTvQ8d-0-9b9603db2ce75761c284c9f353536df6)
代码运行的结果为:
![](https://epubservercos.yuewen.com/2C78EE/26947315207549306/epubprivate/OEBPS/Images/44554_75_4.jpg?sign=1739397883-KGKVZzOp6WenI0W4a39OwUaUKagbNeAi-0-bbb25ffa3ac3fce7d7a6bf3a0e9e90d9)
在我们使用new运算符创建一个数组时,Java会为数组中的每个元素都赋一个初始值,这个初始值根据元素数据类型的不同而不同。如表2-7所示列出了Java 8种基本数据类型的初始值(如果数组中的元素是对象类型,则初始值是null)。
表2-7 Java 8种基本数据类型的初始值
![](https://epubservercos.yuewen.com/2C78EE/26947315207549306/epubprivate/OEBPS/Images/44554_75_5.jpg?sign=1739397883-evTsyayou7LS5gR9BO8hwCO2NI3or6Kp-0-d39868b2405f40727b5459787fa06104)
当我们声明一个包含3个元素的数组,而访问下标为3的元素时,会发生什么情况呢?我们看代码2.30。
代码2.30 ArrayErrors.java
![](https://epubservercos.yuewen.com/2C78EE/26947315207549306/epubprivate/OEBPS/Images/44554_75_6.jpg?sign=1739397883-rXC5tY6flywVppxz3TRmwQXyQTGExRGE-0-b38c157fabb346149e8a7a1f283881f0)
![](https://epubservercos.yuewen.com/2C78EE/26947315207549306/epubprivate/OEBPS/Images/44554_76_1.jpg?sign=1739397883-r2iETnia7nzHjj58ctmSgDTdUYg8DmGe-0-f0752dd25e1bb0a991b7b797f7e0cada)
程序运行的结果为:
![](https://epubservercos.yuewen.com/2C78EE/26947315207549306/epubprivate/OEBPS/Images/44554_76_2.jpg?sign=1739397883-C22jxl5RIeY26F63jNcOpldqv7J52Ykm-0-3b70728cc5e29048cf301a023cd2d7b9)
这时,系统会抛出一个异常,报告数组的下标越界。