文章目录
引言
JAVA数组并不是什么很难的知识,如果单从用法的角度来看,数组的用法并不难,只是很多程序员虽然一直使用JAVA数组,但他们往往对JAVA数组的内存分配把握并不准确。本章正是为了弥补程序员的这部分基本功而做的深入探讨
本课将会深入探讨JAVA数组的静态特征。使用JAVA数组之前必须先对数组对象进行初始化。当数组的所有元素都被分配了合适的内存空间,并指定了初始值时,数组初始化完成。程序以后将不能重新改变数组对象在内存中的位置和大小。
从用法角度来看,数组元素相当于普通变量,程序即可把数组元素的值赋给普通变量,也可以把普通变量的值赋给数组元素。
f本课还将深入分析多维数组的实质,深入理解多维数组和一位数组之间的关联,并通过程序示范如何将一位数组扩展成多维数组。
1.1 数组初始化
数组是大多数编程语言都提供的一种复合结构,如果程序需要多个类型相同的变量时,就可以考虑定义一个数组。Java语言的数组变量是引用类型的变量,因此具有独有的特性
1.1.1 Java数组是静态的
Java语言是典型的静态语言,因此Java的数组是静态的,即当数组被初始化之后,该数组的长度是不可变的。Java程序中的数组必须经过初始化后才可以使用。所谓初始化,就是维数组对象的元素分配内存空间,并为每个数组元素指定初始值。
数组的初始化有以下两种方式:
- 静态初始化:
初始化时由程序员显示指定每个数组元素的初始值,由系统决定数组长度- 动态初始化:
初始化时程序员只指定数组长度,由系统为数组元素分配初始值。
程序清单: codes\01\1.1\ArrayTest.java
public class ArrayTest {
public static void main(String[] args) {
// 采用静态初始化方式初始化第1个数组
String[] books = new String[] { "疯狂Java讲义", "轻量级Java EE企业应用实战", "疯狂Ajax讲义", "疯狂XML讲义" };
// 采用静态初始化的简化形式初始化第2个数组
String[] names = { "孙悟空", "猪八戒", "白骨精" };
// 采用动态初始化的语法初始化第3个数组
String[] strArr = new String[5];
// 访问三个数组的长度
System.out.println("第一个数组的长度: " + books.length);
System.out.println("第二个数组的长度: " + names.length);
System.out.println("第三个数组的长度: " + strArr.length);
}
}
结果如下:
第一个数组的长度: 4
第二个数组的长度: 3
第三个数组的长度: 5
分析
上面的程序代码声明并初始化了3个数组。这3个数组的长度将会始终不变,程序输出3个数组的长度依次为3、4、5
从该图可以看出,对于静态初始化方式而言,程序员无需指定数组长度,指定该数组的数组元素,有系统来决定该数组的长度即可。例如,books数组,为它指定了4个数组元素,那它的长度就是4。
执行动态初始化时,程序员只需要指定数组的长度,即为每个数组元素指定所需的内存空间,系统将负责为这些数组元素分配初始值。指定初始值时,系统将按如下规则分配初始值。
- 数组元素的类型是基本类型中的整数类型(byte , short , int 和long),则数组元素的值是0.
- 数组元素的类型是基本类型中的浮点类型(float, double) , 则数组元素的值是 0.0.
- 数组元素的类型是基本类型中的字符类型(char) , 则数组元素的值是 ‘\u0000’.
- 数组元素的类型是基本类型中的布尔类型(boolean), 则数组元素的值是 false.
- 数组元素的类型是引用类型(类、 接口、 和数组), 则数组元素的值是 Null。
注意:
不要同时使用静态初始化和动态初始化。也就是说,不要再进行数组初始化时,即指定数组的长度,也为每个数组元素分配初始值。
Java的数组是静态的,一旦为数组初始化完成,数组元素的内存空间分配即结束,程序只能改变数组元素的值,而无法改变数组的长度。
需要指出的是,Java的数组变量是一种引用类型的变量,数组变量本身并不是数组本身,它只是指向堆内存中的数组对象。因此,可以改变一个数组变量所引用的数组,这样就可以造成数组长度可变的假象。假设,在上面程序后增加几行。
代码是:
public class ArrayTest {
public static void main(String[] args) {
// 采用静态初始化方式初始化第1个数组
String[] books = new String[] { "疯狂Java讲义", "轻量级Java EE企业应用实战", "疯狂Ajax讲义", "疯狂XML讲义" };
// 采用静态初始化的简化形式初始化第2个数组
String[] names = { "孙悟空", "猪八戒", "白骨精" };
// 采用动态初始化的语法初始化第3个数组
String[] strArr = new String[5];
// 访问三个数组的长度
System.out.println("第一个数组的长度: " + books.length);
System.out.println("第二个数组的长度: " + names.length);
System.out.println("第三个数组的长度: " + strArr.length);
//codes\01\1.1\ArrayTest2.java
//让books数组变量、strArr数组变量指向names所引用的数组
books = names;
strArr = names;
System.out.println("----------------");
System.out.println("books数组的长度:" + books.length);
System.out.println("strArr数组的长度: " + strArr.length);
//改变books 数组变量所引用的数组的第2 个元素值
books[1] = "唐僧";
System.out.println("names数组的第2个元素是:" + books[1]);
}
}
运行结果为:
第一个数组的长度: 4
第二个数组的长度: 3
第三个数组的长度: 5
books数组的长度:3
strArr数组的长度: 3
names数组的第2个元素是:唐僧
解释:
上面程序中粗体字代码将让books数组变量、strArr数组变量都指向names数组变量所引用的数组,这样做的结
果就是books、 strArr 、 names 这3个变量引用同一个数组对象。此时,3个引用变量和数组对象在内存中的
分配如图所示。
从图中可以看出,此时strArr、 names、 和books数组变量实际上引用同一个数组对象。因此,当访问books数组长度、strArr数组长度时,将看到输出3、这很容易造成一个假象:books数组的长度从4变成了3.实际上,数组对象本身的长度并没有发生改变,变得是books数组变量。books数组变量原本指向堆内存下面的数组,当执行了books = names; 语句之后,books数组将改为指向堆内存中间的数组,而原来books变量所引用的数组长度依然是4.
当然,从图中还可以看出,原来books变量所引用的数组长度依然是4,但不再有任何引用变量引用该数组,因此它将会变成垃圾,等着垃圾回收机制来回收。此时,程序使用books、 names、 和 strArr这3个变量时,将会访问同一个数组对象,因此把books数组的第2个元素赋值为“唐僧”时,names 数组的第2个元素的值也会随之改变。与 java这种静态语言不同的是,JavaScript这中动态语言的数组长度是可以动态改变的,示例如下:
上面是一个简单的JavaScript程序。它先定义了一个名为arr的空数组,因为它不包含任何数组元素,所以它的长度为0。接着,为arr数组的第3个、第5个元素赋值,该数组的长度也自动变为5.这就是JavaScript里的动态数组和Java里静态数组的区别
1.1.2 数组一定要初始化吗
使用Java数组之前必须先初始化数组,也就是为数组元素分配内存空间,并指定初始值。实际上,如果真正掌握了Java数组在内存中分配机制,那么完全可以换一个方式来初始化数组,或者说,数组无需经过初始化。
始终记住:Java的数组变量是引用类型的变量,它并不是数组对象本身,只要让数组变量指向有效的数组对象,程序中即可使用该数组变量。实例如下:
代码如下:
public class ArrayTest3 {
public static void main(String[] args) {
// TODO Auto-generated method stub
//定义并初始化nums数组
int[] nums = new int[] {3,5,20,12};
//定义一个prices数组变量
int [] prices;
//让prices 数组指向nums所引用的数组
prices = nums;
for (int i = 0; i < prices.length; i++) {
System.out.println(prices[i]);
}
//将prices数组的第3个元素赋值为34
prices[2] = 34;
//访问nums数组的第3个元素,将看到输出34
System.out.println("nums数组的第三个元素的值是: " + nums[2]);
}
}
运行结果:
3
5
20
12
nums数组的第三个元素的值是: 34
从图中可以看出,此时的prices数组变量还未指向任何有效的内存,为指向任何数组对象,此时的程序还不可使用prices数组变量。
当程序执行prices = nums ;之后,prices变量将指向nums变量所引用的数组,此时prices变量和nums变量所引用同一个数组对象。执行这条语句之后,prices变量已经指向有效的内存及一个长度为4的数组对象,因此程序完全可以正常使用prices变量了。
注意:
常常说使用Java数组之前必须先进行初始化,可是现在prices变量却无需初始化,这不是互相矛盾吗?其实一点都不矛盾。关键是大部分时候,我们把数组变量和数组对象搞混了,数组变量知识一个引用变量(有点类似C语言里的指针),通常存放在栈内存中(也可以被放入堆内存中的);而数组对象就是保存在堆内存中的连续内存空间。对数组执行初始化,其实并不是对数组变量执行初始化,二是要对数组对象执行初始化——也就是为该数组对象分配一款连续的内存空间,这块连续的内存空间的长度就是数组的长度。虽然上面程序中的prices变量看似没有经过初始化,但执行prices = nums;就会让prices变量直接指向一个已经执行初始化的数组
对于数组变量来说,它并不需要进行所谓的初始化,只要让数组变量指向一个有效的数组对象,程序即可正常使用该数组变量
提示
对于Java程序中所有的引用变量,它们都不需要经过所谓的初始化操作。


6039

被折叠的 条评论
为什么被折叠?



