1、 数组初始化
如果程序需要多个类型相同的变量时,就可以考虑定义一个数组。Java语言的数组变量时引用类型的变量,因此具有Java引用变量的特性。
1、1 Java数组静态特性
Java语言是典型的静态语言,因此Java数组是静态的,即当数组被初始化之后,其所占的内存空间、数组长度均是不可变的。Java程序中的数组必须经过初始化后才能够使用,所谓初始化,即创建实际的数组对象,也就是在内存中为数组对象分配空间,并未每个数组元素指定初始值。
数组的初始化有以下两种方式:
-
静态初始化:初始化时由程序员显式指定每个数组元素的初始值,由系统来决定数组长度。
-
静态初始化:初始化时由程序员指定数组长度,由系统为每个数组元素分配初始值。
public class ArrayTest {
public static void main(String[] args) {
String[] books = new String[] { //采用静态初始化方式初始数组
"book1",
"book2",
"book3"
};
String[] strArr = new String[5]; ////采用动态初始化方式初始数组
System.out.println("第一个数组的长度:" + books.length);
System.out.println("第二个数组的长度:" + strArr.length);
}
}
输出结果为:
第一个数组的长度:3
第二个数组的长度:5
Java语言的数组变量时引用类型的变量,books和strArr数组在内存的分配示意图如下所示。
从上图可以知道,对于静态初始化方式,程序员无须指定数组长度,但要指定数组的元素,长度由系统来决定。对于动态初始化方式,程序员只需要指定数组的长度,即为每个数组元素指定所需的内存空间,系统将负责为这些数组元素分配初始值。
注意:不要同时使用静态初始化和动态初始化方式。也就是说,不要再进行数组初始化时,既指定数组的长度,又为每个数组元素分配初始值。
Java数组是静态的,一旦数组初始化完成,数组元素的内存空间分配即结束,程序只能改变元素的值,而无法改变数组长度。需要指出的是,Java的数组变量是一种引用的变量,数组元素并不是数组本身,它只是指向堆内存中的数组对象。因此,可以改变一个数组变量所引用的数组,这样可以造成数组长度可变的假象。
例如:
import java.util.Arrays;
public class ArrayTest2 {
public static void main(String[] args) {
String[] books = new String[] { //采用静态初始化方式初始数组
"book1",
"book2",
"book3"
};
String[] strArr = new String[5]; ////采用动态初始化方式初始数组
strArr = books;
System.out.println("第一个数组的长度:" + books.length);
System.out.println("第二个数组的长度:" + strArr.length);
System.out.println("srtArr:" + Arrays.toString(strArr));
}
}
输出结果为:
第一个数组的长度:3
第二个数组的长度:3
srtArr:[book1, book2, book3]
上面代码中将strArr数组变量指向books数组变量所引用的数组,原来strArr数组变量所引用的数组长度依然是5,但是不再有任何引用变量引用该数组,因此它将会变成垃圾,等着垃圾回收机制来回收。此时,books和strArr数组在内存的分配示意图如下所示。
1、2 关于数组的初始化
Java的数组变量只是引用类型的变量,它并不是数组对象本身,只要让数组变量指向有效的数组对象,程序中即可使用该数组对象。
import java.util.Arrays;
public class ArrayTest3 {
public static void main(String[] args) {
int[] strArr = new int[]{1 , 2 , 3 , 4}; //定义并初始化一个数组
int[] number; //定义一个数组
number = strArr;
System.out.println("number:" + Arrays.toString(number));
number[2] = 5;
System.out.println("strArr:" + Arrays.toString(strArr));
}
}
输出结果为:
number:[1, 2, 3, 4]
strArr:[1, 2, 5, 4]
程序定义了number数组变量之后,并没有立刻进行初始化过程。当程序执行number = strArr;之后,number变量指向strArr变量所引用的数组,此时两个变量都引用同一个数组对象,strArr和number数组在内存的分配示意图如下所示。
注意:对数组执行初始化,其实并不是对数组变量执行初始化,而是在堆内存中创建数组对象,也就是为该数组对象分配一块连续的内存空间,这块连续的内存空间的长度就是数组的长度。上面程序中的number变量在执行number = strArr;之后,会直接指向一个已经存在的数组,因此number变量可以使用。Java程序中的引用变量并不需要经过所谓的初始化操作,需要进行初始化的是引用变量所引用的对象。需要指出的是,Java的局部变量必须由程序员赋初始值,因此如果定义了局部变量的数组变量,程序必须对局部的数据变量进行赋值,即使赋值为null。
1、3 基本类型数组的初始化
对于基本类型数组而言,数组元素的值直接存储在对应的数组元素中。初始化过程为:程序直接先为数组分配内存空间,再将数组元素的值存入对应内存中。
public class ArrayTest4 {
public static void main(String[] args) {
int[] strArr;
strArr = new int[]{1 , 2 , 3 , 4};
}
} 上面代码对应的内存空间示意图如下所示。实际上,不管是基本类型的变量还是引用类型的变量,都是存储在各自的方法栈中的。但引用类型的变量所引用的对象(包括数组、普通Java对象)总是存储在堆内存中。对于Java而言,堆内存中的对象通常是不允许直接访问的,为了访问堆内存中的对象,通常只能通过引用变量。
1、4 引用类型数组的初始化
引用类型数组的数组元素依然是引用类型,因此数组元素里存储的还是引用,它指向另一块内存,这块内存里存储了该引用变量所引用的对象。
class Person{
public int age; //年龄
public double height; //身高
public void info() { //自我介绍
System.out.println("年龄:" + age + ",身高:" + height);
}
}
public class ArrayTest5 {
public static void main(String[] args) {
Person[] students = new Person[2]; //定义并初始化数组
Person li = new Person(); //创建一个Person实例,并赋给li变量
li.age = 13;
li.height = 120.3;
Person wang = new Person(); //创建一个Person实例,并赋给wang变量
wang.age = 17;
wang.height = 160.5;
students[0] = li; //将li变量的值赋给第一个数组元素
students[1] = wang; //将wang变量的值赋给第二个数组元素
students[0].info();
students[1].info();
}
}
输出结果为:
年龄:13,身高:120.3
年龄:17,身高:160.5
执行代码之后,li和students[0]指向同一个内存去,而且它们都是引用类型的变量,因此通过li和students[0]来访问Person实例的属性和方法效果完全一样,同时,无论修改li还是students[0]的属性或者方法,势必也会相互影响,因为修改的其实是同一块内存区域。同理,wang和students[1]也是同样的效果。内存示意图如下所示。
本文详细介绍了Java中数组的初始化过程,包括静态初始化和动态初始化两种方式,并解释了数组的静态特性。通过示例代码展示了不同初始化方式的具体实现及注意事项。
1395

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



