在计算机语言中数组是非常重要的集合类型,大部分计算机语言中数组具有如下三个基本特性:
在Java中数组的下标是从零开始的,事实上很多计算机语言的数组下标从零开始的。Java数组下标访问运算符是中括号,如intArray[0],表示访问intArray数组的第一个元素,0是第一个元素的下标。
另外,Java中的数组本身是引用数据类型,它的长度属性是length。数组可以分为:一维数组和多维数组,下面先介绍一维数组。
当数组中每个元素都只带有一个下标时,这种数组就是“一维数组”。数组是引用数据类型,引用数据类型在使用之前一定要做两件事情:声明和初始化。
数组的声明就宣告这个数组中元素类型,数组的变量名。
注意 数组声明完成后,数组的长度还不能确定,JVM(Java虚拟机)还没有给元素分配内存空间。
数组声明语法如下:
元素数据类型[] 数组变量名;
元素数据类型 数组变量名[];
可见数组的声明有两种形式:一种是两个中括号([])跟在元素数据类型之后;另一种是两个中括号([])跟在变量名之后。
提示 从面向对象角度看,Java更推荐采用第一种声明方式,因为它把“元素数据类型[]”看成是一个整体类型,即数组类型。而第二种是C语言数组声明方式。
数组声明示例如下:
int intArray[]; float[] floatArray; String strArray[]; Date[] dateArray;
声明完成就要对数组进行初始化,数组初始化的过程就是为数组每一个元素分配内存空间,并为每一个元素提供初始值。初始化之后数组的长度就确定下来不能再变化了。
提示 有些计算机语言虽然提供了可变类型数组,它的长度是可变的,这种数组本质上是创建了一个新的数组对象,并非是原始数组的长度发生了变化。
数组初始化可以分为静态初始化和动态初始化。
静态初始化就是将数组的元素放到大括号中,元素之间用逗号(,)分隔。示例代码如下:
int[] intArray; //静态初始化int数组 intArray = {21,32,43,45}; String[] strArray; //静态初始化Stirng数组 strArray = {"张三","李四","王五","董六"}; //声明同时初始化数组 int intArray[] = {21,32,43,45}; String strArray[] = {"张三","李四","王五","董六"};
静态初始化是在已知数组的每一个元素内容情况下使用的。很多情况下数据是从数据库或网络中获得的,在编程时不知道元素有多少,更不知道元素的内容,此时可采用动态初始化。
动态初始化使用new运算符分配指定长度的内存空间,语法如下:
new 元素数据类型[数组长度] ;
示例代码如下:
int intArray[]; // 动态初始化int数组 intArray = new int[4]; ① intArray[0] = 21; intArray[1] = 32; intArray[2] = 43; intArray[3] = 45; ② // 动态初始化String数组 String[] stringArray = new String[4]; ③ // 初始化数组中元素 stringArray[0] = "张三"; stringArray[1] = "李四"; stringArray[2] = "王五"; stringArray[3] = "董六"; ④
上述代码第①行和第③行通过new运算符分配了4个元素的内存空间。
提示 new分配数组内存空间后,数组中的元素内容是什么呢?答案是数组类型的默认值,不同类型默认值是不同的,如表8-1所示。
表 8-1 数据类型默认值
* 基本类型 * | * 默认值 * |
---|---|
byte | 0 |
short | 0 |
int | 0 |
long | 0L |
float | 0.0f |
double | 0.0d |
char | '/u0000' |
boolean | false |
引用 | null |
当代码第①行执行完成,intArray数组内容如图8-1(a)所示,intArray数组中的所有元素都是0,根据需要会动态添加元素内容,代码第②行执行完成,intArray数组内容如图8-1(b)所示。
当代码第③行执行完成,stringArray数组内容如图8-2(a)所示,stringArray数组中所有元素都是null,随着每一个元素被初始化和赋值,代码第④行执行完之后每个元素都有不同内容,这里需要注意的是引用类型数组,每一个元素保存都是指向实际对象的内存地址,如图8-2(b)所示,每个对象还需要创建和初始化过程,有关对象创建和初始化内容,将在后面章节详细介绍。
数组长度是不可变,要想合并两个不同的数组,不能通过在一个数组的基础上追加另一个数组实现。需要创建一个新的数组,新数组长度是两个数组长度之和。然后再将两个数组的内容导入到新数组中。
下面具体看看实现代码:
public class HelloWorld { public static void main(String[] args) { // 两个待合并数组 int array1[] = { 20, 10, 50, 40, 30 }; int array2[] = { 1, 2, 3 }; // 动态初始化数组,设置数组的长度是array1和array2长度之和 int array[] = new int[array1.length + array2.length]; // 循环添加数组内容 for (int i = 0; i < array.length; i++) { if (i < array1.length) { ① array[i] = array1[i]; ② } else { array[i] = array2[i - array1.length]; ③ } } System.out.println("合并后:"); for (int element : array) { System.out.printf("%d ", element); } } }
上述代码第①行是判断当前循环变量i是否小于array1.length,在此条件下将array1数组内容导入新数组,见代码第②行。当array1数组内容导入完成后,再通过代码第③行将另一个数组array2导入到新数组,其中array2下标应该是i - array1.length。
当数组中每个元素又可以带有多个下标时,这种数组就是“多维数组”。本节重点介绍二维数组。
Java中声明二维数组需要有两个中括号,具体有三种语法如下:
元素数据类型[][] 数组变量名;
元素数据类型 数组变量名[][];
元素数据类型[] 数组变量名[];
三种形式中前两种比较好理解,最后一种形式看起来有些古怪。数组声明示例如下:
int[][] array1; int array1[][]; int[] array1[];
二维数组的初始化也可以分为静态初始化和动态初始化。
静态初始化示例如下:
int intArray[][] = { { 1, 2, 3 }, { 11, 12, 13 }, { 21, 22, 23 }, { 31, 32, 33 } };
上述代码创建并初始化了一个4×3二维数组,理解Java中的多维数组应该从数组的数组的角度出发。首先将intArray看成是一个一维数组,它有4个元素,如图8-3所示,其中第1个元素是{ 1, 2, 3 },第2个元素是{ 11, 12, 13 },第3个元素是{ 21, 22, 23 },第4个元素是{ 31, 32, 33 }。然后再分别考虑每一个元素,{ 1, 2, 3 }表示形式说明它是一个int类型的一维数组,其他3个元素也是一维int类型数组。
提示 严格意义上说Java中并不存在真正意义上的多维数组,只是一维数组,不过数组中的元素也是数组,以此类推三维数组就是数组的数组的数组了,例如{ { {1, 2}, {3} }, { {21}, {22, 23} } }表示一个三维数组。
动态初始化二维数组语法如下:
new 元素数据类型[高维数组长度] [低维数组长度] ;
高维数组就是最外面的数组,低维数组是每一个元素的数组。动态创建并初始化一个4×3二维数组示例代码如下:
int[][] intArray = new int[4][3];
二维数组的下标[4][3]有两个,前面的[4]是高维数组下标索引,后面的[3]是低维数组下标索引。4×3二维数组的每一个元素的下标索引,如图8-4(a)所示。由于低维数组是int类型,所以初始化完后所有元素全部是0,如图8-4(b)所示。
二维数组示例如下:
public class HelloWorld { public static void main(String[] args) { // 静态初始化二维数组 int[][] intArray = { { 1, 2, 3 }, { 11, 12, 13 }, { 21, 22, 23 }, { 31, 32, 33 } }; // 动态初始化二维数组 double[][] doubleArray = new double[4][3]; // 计算数组intArray元素的平方根,结果保存到doubleArray for (int i = 0; i < intArray.length; i++) { for (int j = 0; j < intArray[i].length; j++) { // 计算平方根 doubleArray[i][j] = Math.sqrt(intArray[i][j]); ① } } // 打印数组doubleArray for (int i = 0; i < doubleArray.length; i++) { for (int j = 0; j < doubleArray[i].length; j++) { System.out.printf("[%d][%d] = %f", i, j, doubleArray[i][j]); System.out.print( /t ); } System.out.println(); } } }
代码第①行是中Math.sqrt(intArray[i][j])表达式是计算平方根,Math是java.lang包中提供的用于数学计算类,它提供很多常用的数学计算方法,sqrt是计算平方根,如取绝对值的abs、幂运算的pow等。
由于Java多维数组是数组的数组,因此会衍生出一种不规则数组,规则的4×3二维数组有12个元素,而不规则数组就不一定了。如下代码静态初始化了一个不规则数组。
int intArray[][] = { { 1, 2 }, { 11 }, { 21, 22, 23 }, { 31, 32, 33 } };
高维数组是4个元素,但是低维数组元素个数不同,如图8-5所示,其中第1个数组有两个元素,第2个数组有1个元素,第3个数组有3个元素,第4个数组有3个元素。这就是不规则数组。
动态初始化不规则数组比较麻烦,不能使用new int[4][3]语句,而是先初始化高维数组,然后再分别逐个初始化低维数组。代码如下:
int intArray[][] = new int[4][]; //先初始化高维数组为4 //逐一初始化低维数组 intArray[0] = new int[2]; intArray[1] = new int[1]; intArray[2] = new int[3]; intArray[3] = new int[3];
从上述代码初始化数组完成之后,不是有12个元素而是9个元素,它们的下标索引如图8-6所示,可见其中下标[0][2]、[1][1]和[1][2]是不存在的,如果试图访问它们则会抛出下标越界异常。
提示 下标越界异常(ArrayIndexOutOfBoundsException)是试图访问不存在的下标时引发的。例如一个一维array数组如果有10个元素,那么表达式array[10]就会发生下标越界异常,这是因为数组下标是从0开始的,最后一个元素下标是数组长度减1,所以array[10]访问的元素是不存在的。
下面介绍一个不规则数组的示例:
public class HelloWorld { public static void main(String[] args) { int intArray[][] = new int[4][]; //先初始化高维数组为4 //逐一初始化低维数组 intArray[0] = new int[2]; intArray[1] = new int[1]; intArray[2] = new int[3]; intArray[3] = new int[3]; //for循环遍历 for (int i = 0; i < intArray.length; i++) { for (int j = 0; j < intArray[i].length; j++) { intArray[i][j] = i + j; } } //for-each循环遍历 for (int[] row : intArray) { ① for (int column : row) { ② System.out.print(column); //在元素之间添加制表符, System.out.print( /t ); } //一行元素打印完成后换行 System.out.println(); } //System.out.println(intArray[0][2]); //发生运行期错误 ③ } }
不规则数组访问和遍历可以使用for和for-each循环,但要注意下标越界异常发生。上述代码第①行和第②行采用for-each循环遍历不规则数组,其中代码第①行for-each循环取出的数据是int数组,所以row类型是int[]。代码第②行for-each循环取出的数据是int数据,所以column的类型int。
另外,注意代码第③行试图访问intArray[0][2]元素,由于[0][2]不存在所以会发生下标越界异常。
本章介绍了Java的数组,包括一维数组和多维数组,读者要重点掌握一维数组的声明、初始化和使用,了解二维数组的声明、初始化和使用。另外,还需要了解不规则数组。
https://edu.csdn.net/combo/detail/822
http://www.zhijieketang.com/group/5