数组与内存控制
1.数组初始化
Java的数组变量是引用类型的变量
1.1Java数组是静态的
Java语言是典型的静态语言,因此Java数组是静态的,即当数组被初始化后,该数组长度是不可变的。Java数组必须初始化后才可以使用。所谓初始化,就是为该数组元素分配内存空间,并为每个元素指定初始值。
数组的初始化有以下两种方式:
- 静态初始化:初始化时由程序员显式指定每个数组元素的初始值,由系统决定数组长度。
- 动态初始化:初始化时程序员只指定数组长度,由系统为数组元素分配初始值。
public static void main(String[] args) {
//采用静态初始化第一个数组
String[] books = new String[]{
"book1","book2","book3","book4"
};
//采用静态初始化的简化形式初始化第二个数组
String[] names = {"name1", "name2", "name3"};
//采用动态初始化 初始第三个数组
String[] strArr = new String[5];
System.out.println("第一个数组的长度:" + books.length);
System.out.println("第二个数组的长度:" + names.length);
System.out.println("第三个数组的长度:" + strArr.length);
}
程序输出3个数组的长度依次为4,3,5
数组在堆内存中的示意图
执行初始化时,程序员只需指定数组的长度,即为每个数组元素指定所需的内存空间,系统将负责为这些数组元素分配初始值。指定初始值时,系统将按如下规则分配初始值。
- 数组元素的类型是基本类型中的整数类型(byte、short、int、long),则数组元素的值是0.
- 数组元素的类型是浮点类型(float、double),则数组元素的值是0.0。
- 数组元素的类型是字符类型(char),则数组元素的值是‘\u0000’。
- 数组元素的类型是基本类型的布尔类型(boolean),则数组元素的值是false。
- 数组元素的类型是引用类型(类、接口、数组),则数组元素的值是null
注意
不可同时使用静态初始化和动态初始化。也就是说,不要在进行数据初始化时,既指定数组的长度,也为每个数组元素分配初始值。
1.2数组一定要初始化吗?
Java的数组变量是引用类型的变量,它不是数组对象本身,只要让数组变量指向有效的数组对象,程序中即可使用该数组变量。
public static void main(String[] args) {
//定义并初始nums数组
int[] nums = new int[]{3,4,5,6};
//定义一个prices变量
int[] prices;
// 让prices数组指向nums所引用的数组
prices = nums;
for (int i = 0; i < prices.length; i++){
System.out.println(prices[i]);
}
// 将prices的第3个值赋值为9
prices[2] = 9;
// 访问nums数组的第3个元素,输出为 9
System.out.println("nums数组的第3个元素的值 :" + nums[2]);
}
当执行 prices=nums;之后,prices变量指向nums变量所引用的数组,此时prices变量和nums变量引用同一个数组对象。
注意
数组变量只是一个引用变量,通常存放于栈内存中;而数组对象就是保存在堆内存的连续内存空间。对数组执行初始化,其实并不是对数组变量执行初始化,而是要对数组对象执行初始化——也就是为该数组对象分配一块连续的内存空间,这块连续的内存空间的长度就是数组的长度。
对于数组来说,它并不需要所谓的初始化,只要让数组变量指向一个有效的数组对象,程序即可正常使用该数组变量。
1.3基本数据类型数组的初始化
对于基本数据类型而言,数组元素的值直接存储在对应的数组元素中,因此基本类型数组的初始化比较简单:程序直接先为数组分配内存空间,再将数组元素的值存入对应内存里。
例如:
public static void main(String[] args) {
// 定义一个int[] 类型的数组变量
int[] iArr;
// 静态初始化数组,数组长度为4
iArr = new int[]{2, 3, 4, 5};
}
静态初始化完成后,iArr数组变量所引用的数组所占用的内存空间被固定下来,程序员只能改变个数组元素中的值,但不能移动该数组所占用的内存空间——既不能扩大该数组对象所占用的内存,也不能缩减该数组对象所占用的内存。
所有局部变量都是放在栈内存里保存的,不管其是基本类型变量还是引用类型变量,都是存储在各自的方法栈中;但引用类型所引用的对象(包括数组、普通Java对象)则总是存储在堆内存中。
对于Java语言而言,堆内存中的对象(不管是数组对象还是普通的Java对象)通常不允许直接访问,为了访问堆内存中的对象,通常只能通过引用变量。
1.4引用类型数组的初始化
引用类型数组的数组元素依然是引用类型的,因此数组元素里存储的还是引用,它指向另一块内存,这块内存里存储了该引用变量所引用的对象(包括数据和Java对象)。
public static void main(String[] args) {
// 定义一个students数组变量,类型是Person[]
Person[] students;
//执行动态初始化
students = new Person[2];
System.out.println("students所引用的数组的长度是:" + students.length);
//创建2个Person 实例
Person zhang = new Person();
zhang.age = 15;
zhang.height = 170;
Person lee = new Person();
lee.age = 16;
lee.height = 140;
// 将zhang 的变量赋给第1个数组元素
students[0] = zhang;
// 将lee 的变量赋给第2个数组元素
students[1] = lee;
// 下面两行代码完全一样,指向同一个实例
lee.info();
students[1].info();
}
}
class Person{
int age;
double height;
public void info(){
System.out.println("年龄是:" + age + ", 身高是:" + height);
}
}
2.使用数组
当数组引用变量指向一个有效的数组对象之后,程序就可通过该数组引用变量来访问数组对象。
2.1数组元素就是变量
只要在已有的数据类型之后增加方括号,就会产生一个新的数组类型,如下
- int-> int[]:在int类型后增加[]即变为int[]数组类型。
- String-> String[]:在String类型后增加[]即变为String[]数组类型。
- Person-> Person[]:在Person类型后增加[]即变为Person[]数组类型。
- int[]-> int[][]:在int[]类型后增加[]即变为int[][]数组类型。
当通过索引来使用数组元素时,将数组元素当成普通变量使用即可,包括访问该数组元素的值,为数组元素赋值等。
2.2没有多维数组
只要在已有数据类型之后增加方括号,就会产生一个新的数组类型。如果已有的类型是int,增加方括号是int[]类型,这是一个数组类型;如果再以int[]类型为已有类型,增加方括号就得到int[ ][ ]类型,这依然是数组类型;如果再以int[ ][ ]类型为已有类型,增加方括号就得到int[ ][ ][ ]类型,这依然是数组类型。
反过来,将数组类型最后的方括号去掉就得到了数组元素的类型。对于int[ ][ ][ ]类型的数组,其数组元素就相当于int[ ][ ]类型的变量;对于int[ ][ ]类型的数组,其数组元素就相当于int[ ]类型的变量;对于int[ ]类型的数组,其数组元素就相当于int类型的变量。
从上面分析可以看出,所谓多维数组,其实只是数组元素依然是数组的1 维数组,2 维数组是数组元素是1维数组的数组,3维数组是数组元素是2维数组的数组,4维数组是数组元素是3维数组的数组……N维数组是数组元素是N-1维数组的数组。
Java允许将多维数组当成1维数组处理。初始化多维数组时可以先只初始化最左边的维数,此时该数组的每个元素都相当于一个数组引用变量,这些数组元素还需要进一步初始化。