在上一篇教程中我们主要一起来学习了如何声明并初始化一个数组类型的变量,也知道了可以通过索引操作(如[0])来访问数组的某个元素。接下来我们继续学习一些有关数组的常见用法,比如如何来更改某个数组的大小。
无论是使用隐式初始化,或者是显式初始化,一旦数组完成初始化后,其大小就固定了。
int[] userAges = {22, 27, 25, 30, 28};
在这段代码中,int型数组userAges只能存储5个数据,我们可以在编写代码时使用索引[0]、[1]、[2]、[3]、[4]来分别访问或者更改这五个元素。如果不小心像下面这样编写了代码
System.out.println(userAges[5]);
那么当在IntelliJ IDEA中运行这段完整代码时
public class ArrayDemo2 {
public static void main(String[] args) {
int[] userAges = {22, 27, 25, 30, 28};
System.out.println(userAges[5]);
}
}
在输出窗口里面就会显式一些错误信息,比如“Index 5 out of bounds for length 5”,这告诉我们索引5操过了数组的长度。在编程术语里面,这类现象往往叫做索引越界。
如果将代码里面的索引5更改成4,再次运行这段代码,输出窗口里面的错误信息就不再出现,并在屏幕上打印数组userAges的第五个元素28。
public class ArrayDemo2 {
public static void main(String[] args) {
int[] userAges = {22, 27, 25, 30, 28};
// System.out.println(userAges[5]);
System.out.println(userAges[4]);
}
}
在上一篇教程中,我们像下面这样重复地编写代码来打印数组的所有元素,
System.out.println(userAges[0]);
System.out.println(userAges[1]);
System.out.println(userAges[2]);
System.out.println(userAges[3]);
System.out.println(userAges[4]);
这仅仅是为了教学示例,Java程序员在实际编写这类代码时不会这样做,而是会使用循环,比如像下面这样,
for (int i = 0; i < userAges.length; i++) {
System.out.println(userAges[i]);
}
除了“userAges.length”这个用法,上面这段代码的其他部分我们现在都能够很容易的理解。因为在Java中,数组类型与整数类型、浮点数类型或者字符类型的变量不同,前者是复合类型,后者是基本类型。复合类型内部可以包含其他复合类型或者基本类型。以数组为例,其内部包含一个int型的属性length,用来记录数组的大小、长度。关于什么是属性,现在大家不需要过多了解,后面在学习到面向对象编程时会深入学习这方面知识。
如果要使用内部属性,我们在编写代码时就要用到点操作符”.”,也叫做访问操作符。这类用法我们其实很早就有接触,比如通过代码“.println()”来使用out复合类型变量的内部属性,同时out这个复合类型又是System这个复合类型的一个内部属性。
对于数组这类“容器”,Java还支持另外一个形式的for循环语句。
for (int userAge : userAges) {
System.out.println(userAge);
}
在这段代码中,for语句会循环依序地遍历数组userAges的每个成员,并将其赋值给变量userAge。如果大家运行这段代码,屏幕上会打印
22
27
25
30
28
我们也可以在数组完成初始化后,根据需要再重新更改其大小。假设有这样一个情景,原计划是声明一个大小为30的数组来记录班级里所有学生的学号,后面发现需要扩大,比如有转校生的加入,那么可以这样编写代码,
int[] studentIDs = new int[30];
System.out.println(studentIDs.length);
studentIDs = new int[35];
System.out.println(studentIDs.length);
第一行语句中,考虑到当前暂时没有转校生加入班级,因此采用隐式初始化方式声明了一个int型数组studentIDs,大小为30。第三行语句中,后面发现会有5个转校生的加入,因此需要将数组扩大到35。
需要进一步说明的是,现在我们知道数组在内存中是以连续的存储空间的形式存放的,因此第一行语句会将内存中某一段能够存储30个int型整数的存储空间分配给变量studentIDs使用;第三行语句,我们再次使用new操作符告诉电脑,将内存中另外一段能够存储35个int型整数的存储空间分配给变量studentIDs。
这两段存储空间严格意义上不会有交叉。实际运行程序的时候,如果Java发现没有任何其他变量在使用第一段存储空间,那么Java会负责将其回收,便于留给后续其他变量使用。这主要由Java的垃圾回收机制来负责。
上面这段代码只是作为教学示例使用,用来告诉大家数组的大小可以在数组初始化完成后,再次更改。实际开发程序的时候往往不会这样编写代码,我们要么会声明一个大小足够大又比较合适的数组,或者迫不得已要更改数组大小的时候,也会先声明一个临时变量用来备份原来的数组,然后将数组的大小扩大或者缩小,最后将数据从临时变量再拷贝回来,比如像下面这样,
int[] smallArray = new int[5];
for (int i = 0; i < smallArray.length; i++) {
smallArray[i] = i * i;
System.out.print(smallArray[i]);
System.out.print(" ");
}
System.out.println();
int[] tempArray = smallArray;
smallArray = new int[10];
for (int i = 0; i < tempArray.length; i++) {
smallArray[i] = tempArray[i];
System.out.print(smallArray[i]);
System.out.print(" ");
}
for (int i = tempArray.length; i < smallArray.length; i++) {
smallArray[i] = i * i;
System.out.print(smallArray[i]);
System.out.print(" ");
}
System.out.println();
第一行语句我们声明了一个大小为5的int型数组smallArray。在第二行到第六行的for语句中,分别将数组的五个元素赋值为0、1、2、3、4这五个数的平方,赋值完成后同时将每个元素打印出来。
第八行语句的用法我们目前为止还没有碰到过,这揭示了在编写代码时除了可以通过隐式初始化或者显式初始化来初始化一个数组变量,还可以将其他数组赋值给某个数组。需要说明的是,这里的用语“赋值”其实并没有将数组smallArray的所有元素赋给新数组tempArray,仅仅是告诉电脑现在数组tempArray和数组smallArray一样可以使用同一段内存空间。
第九行语句使用new操作符重新为变量smallArray分配了另外一段内存空间,这段新的内存空间可以存储10个int型整数。现在数组tempArray还是可以使用原来那段长度为5的内存空间,但是数组smallArray只能使用新分配的这段长度为10的内存空间。而且经过隐式初始化后,数组smallArray的10个元素都是0。
接下来在第十行到第十四行的for语句中,我们将数组tempArray的所有5个元素赋值给数组smallArray的前五个元素,这里才是真正意义上的赋值操作。
在第十五行到十九行的最后一个for语句中,我们将数组smallArray的余下五个元素分别赋值为5、6、7、8、9这五个数的平方。
如果大家运行这段代码,屏幕上会打印
0 1 4 9 16
0 1 4 9 16 25 36 49 64 81
不知不觉中本节教程的知识点就很多了,为了让大家好好消化,暂时就只涉及前面的知识点,其他有关数组的常见用法放到下一篇教程来学习。
下面贴上本节教程的完整代码,
public class ArrayDemo2 {
public static void main(String[] args) {
int[] userAges = {22, 27, 25, 30, 28};
// System.out.println(userAges[5]);
System.out.println(userAges[4]);
System.out.println("=================");
// 使用循环语句来打印数组的所有元素
for (int i = 0; i < userAges.length; i++) {
System.out.println(userAges[i]);
}
System.out.println("=================");
for (int userAge : userAges) {
System.out.println(userAge);
}
System.out.println("=================");
int[] studentIDs = new int[30];
System.out.println(studentIDs.length);
studentIDs = new int[35];
System.out.println(studentIDs.length);
System.out.println("=================");
int[] smallArray = new int[5];
for (int i = 0; i < smallArray.length; i++) {
smallArray[i] = i * i;
System.out.print(smallArray[i]);
System.out.print(" ");
}
System.out.println();
int[] tempArray = smallArray;
smallArray = new int[10];
for (int i = 0; i < tempArray.length; i++) {
smallArray[i] = tempArray[i];
System.out.print(smallArray[i]);
System.out.print(" ");
}
for (int i = tempArray.length; i < smallArray.length; i++) {
smallArray[i] = i * i;
System.out.print(smallArray[i]);
System.out.print(" ");
}
System.out.println();
}
}