本文是《Java学习指南》原书的网络版,作者邵发,拥有本书的全部权利。相关视频课程在此查看。
目录
第5章 数组对象
5.1 数组
本章引入数组的概念。为了方便大家的理解,先给出一个引例。
假设一个班有30个学生,为了表示某次考试的成绩,可能需要定义30个变量。例如,
int a0 = 98;
int a1 = 89;
int a2 = 92;
... 写30行 ...
int a29 = 94;
即,从 a0到a29共30个变量,分别表示这30个学生的成绩。显然,这么样的定义很不科学:如果一个学校有一万个学生,难道要定义一万个变量吗?
5.1.1 数组的概念
在Java语言里,数组对象可以表示一组数字。
例如,
int[ ] arr = new int [ 30 ] ;
其中,定义了一个对象arr,类型为int[]。 右侧的关键字new表示创建对象。简单的讲,就是创建一个可以容纳30个int的数组对象。
初学者在这里只需要强行记住这种形式,多写几次就习惯的。
小结一下就是,
v 对象名称: arr
v 元素类型: int[] (即数组对象)
v 数据长度: 30, 即容纳30个数
创建一个数组对象(Array Object),长度为30,存储的数据类型为int。
3.1.1 数组元素的访问
arr[0] 表示第一个元素
arr[1] 有示第二个元素
...
arr[29] 表示最后一个元素
其中,第 i 个元素用 arr[i] 表示,i称为 索引 (index) 或 下标 (subscript) 。注意下标是从0开始的,例如 0, 1, 2, ..., 29。
使用下标读取某个元素的值,例如,
int s = arr[0] + arr[1] ; // 前2个元素的值
使用下标修改某个元素的值,例如,
arr[7] = 99; // 第八个元素的值修改为99
5.1.2 数组的遍历
所谓遍历,是指从头到尾、挨个访问每个元素。遍历是Java编程里的常见操作。
例如:已知一个数组,要求打印出数组中所有的数值,
int[] arr = new int[4];
arr[0] = 12;
arr[1] = 98;
arr[2] = 82;
arr[3] = 29;
for (int i = 0; i < 4; i++)
{
System.out.print(arr[i] + " ");
}
使用for循环,从头到尾访问每个元素,这就叫做遍历。
当然,也可以从尾到头反方向遍历,例如,
int[] arr = new int[4];
arr[0] = 12;
arr[1] = 98;
arr[2] = 82;
arr[3] = 29;
for (int i = 3; i >=0 ; i--)
{
System.out.print(arr[i] + " ");
}
遍历在我们将来的编程中将经常使用。再给出一个例子:已知一个数组,求数组中每个元素的和。
int[] arr = new int[4];
arr[0] = 12;
arr[1] = 98;
arr[2] = 82;
arr[3] = 29;
int result = 0; //
for( int i=0; i<4; i++)
{
result += arr[i];
}
System.out.println("结果为: " + result);
5.1.3 数组的初始化
默认的,当数组用 new 创建时,所有元素的值为0
例如,
int[] a1 = new int[4];
double[] a2 = new double[4];
则a1和a2中所有元素的值都是0。
另一种情况,在创建创组的时候可以初始化,例如,
int[] arr = { 98, 89, 98, 87 } ;
则创建了一个数组,并同时指定了每个元素的值。
5.1.4 数组的长度
已知数组对象 :
int[] arr = { 98, 89, 98, 87 } ;
则数组的长度可以用 arr.length 来表示。在遍历时,可以用arr.length来表示数组的长度。形如,
for (int i= 0; i< arr.length ; i++)
{
}
初学者应该强记住这种写法,即 数组名.length ,其具体原理在后面的学习过程中自会明白。
5.1.5 数组的打印输出
在打印一个数组的值时,不同初学者会犯以下的错误。例如,
int[] arr = { 98, 89, 98, 87 } ;
System.out.println("数组的值: " + arr); // 错误!
数组对象是不能直接用于打印输出的。应该改成用for语句实现,例如,
for (int i = 0; i < 4; i++)
{
System.out.print(arr[i] + " ");
}
5.2 数组的使用
初学者在开始使用数组时,有可能会遇到一个错误:ArrayIndexOutOfBoundsException,即数组下标越界。例如,
int[] arr = { 98, 89, 98, 87 };
arr[4] = 128; // 这行有错
在运行这段代码时,Eclipse会提示以下错误,
其原因是,长度为N的数组,其下标范围应该是0,1,..., N-1。如果在代码中下标超出了这个范围,就称为数组下标越界。所以,当大家看到ArrayIndexOutOfBoundsException这个错误提示时,就应该明白错误的原因。
在上段代码中,数组arr的长为为4,所以有效的下标是从arr[0]到arr[3]。上例中的arr[4]是错误的写法。
再举一个例子。例如,在遍历时常见犯的错误
int[] arr = { 98, 89, 98, 87 };
for ( int i=0; i <= arr.length; i++) // 错误!
{
System.out.println(arr[i]);
}
在遍历时,如果不小心把 i<arr.length 写成了 i<= arr.length,那么就会报告数组下标越界的错误。
5.2.1 数组的应用举例
例,以下有四个学生的信息,请用数组表示:
姓名 分数
------------------------------------------------------------
邵 97
王 89
张 94
李 93
分析一下:有这两组信息,一组为姓名,一组为分数。所以可以定义两个数组,分别表示姓名和分数。
代码如下,
String[] names = {"邵", "王", "张", "李" };
int[] scores = { 97, 89, 94, 93 };
for(int i=0; i <names.length; i++)
{
System.out.println( names[i] + ", " + scores[i] );
}
5.3 对象与引用
本节介绍一个比较重要的概念:对象与引用。
先看一个例子,
① int[] a = { 11, 11, 11, 11 };
② int[] b = a;
③ b[3] = 45;
④ for(int i=0; i<a.length; i++)
{
⑤ System.out.print( a[i] + " ");
}
其中,
第①行,创建了一个数组对象a,
第②行,又定义了另一个b对象,
第③行,修改了b[3]。这里修改的是b,那么a的值不变是吗?
第⑤行,实际输出的是11 11 11 45,说明对b的修改会同时影响a的内容。为什么呢?
5.3.1 对象与引用的概念
在Java语言里,对象(Object)是一个基础概念。
int[] a = new int[4];
在此式中,等号右侧创建了一个数组对象,等号左侧的变量 a 称为该对象的引用 ( Reference)。
一般来说,可以以称作“变量a 指向了一个对象”,或者简称为“a是一个对象, 其中a是对象的名字”。
多个变量可以指向同一个对象,例如,
int[] a = new int[4];
int[] b = a;
b[3] = 45;
由于a,b指向的是一个对象,所以修改b[3],就等同于修改a[3]。
这就好比,“邵发”指的是作者,“阿发你好”指的也是作者。一个人可以有多个名字。
5.3.2 空对象 null
在Java语言里,有一种特殊的对象,称为“空对象”。例如,
int[] a = null;
其中,a指向一个空对象,其实就是说a不指向任何对象。
理解以下几行代码:
① int[] a = new int[4];
② int[] b = a;
③ a = null;
其中,
第①行,创建了一个对象,命名为a
第②行,b和a指向同一个对象
第③行,a指向null。此时,a不指向任何对象,而b指向刚才创建的对象。
5.3.3 空指针错误 NullPointerException
在经常的编程时,可能经常会遇到一个错误:NullPointerException,即空指针错误。
例如,
int[] a = { 11, 11, 11, 11 };
a = null;
a [0] = 12; // 出错!!
运行这段代码时,将提示出错,如下图所示,
这是因为,当运行到第2行时,a即成为空对象。所以第3行对a[0]的访问就是不合逻辑的,因为此时 a 已经不指向任何对象。
5.3.4 失去引用的对象
观察以下代码:
① int[] a = { 8, 8, 8 };
② a = new int[4];
③ a[0] = a[1] = a[2] = a[3] = 17;
其中,
第①行,创建了一个数组对象,内容为{ 8,8,8}
第②行,创建另一个数组对象, 内容{ 0,0,0,0 }
问题来了,当执行完第②后,曾经创建的第一个对象就没有任何变量引用它了,称为“失去引用”的对象。
当一个对象失去引用后,由于不再会被使用,所以会由系统自动回收销毁这个对象。此过程为称垃圾加收(Garbage Collection, GC )。
所以,在Java里我们只能见到对象的创建(new就是创建对象),而见不到对象的销毁,就是因为对象在失去引用之后会被系统自动回收。
最后再看一个例子体会一下,
int [] a = new int[4];
a = new int[5];
a = new int[5];
在这段代码里,一共创建了3个对象,但前两个对象都失去的引用,会被系统自动回收。