数组的引用变量和内存分配
数组是一种引用类型,数组用来存储同一种数据类型的数据,一旦初始化完成,即所占的空间就已固定下来,即使某个元素被清空,但其所在空间仍然保留,因此数组长度将不能被改变。
数组变量只有分配内存空间后才可以使用。
数组初始化分为静态初始化(在定义时就指定数组元素的值,此时不能指定数组长度,否则就出现了静态加动态混搭初始化数组了)
动态初始化(只指定数组长度,由系统分配初始值,初始值根据定义的数据类型来)。
不要出现静态初始化跟动态初始化混搭比如new int[4]{1,3,4,5}
public class TestDemo { public static void main(String[] args) { //动态初始化 int[] numbers = new int[4]; numbers[0] = 1; for (int i : numbers) { System.out.println(i); } System.out.println("---------------"); //静态初始化 numbers = new int[] {1,2,3,6}; for (int i : numbers) { System.out.println(i); } } }
数组引用变量是存放在栈内存(stack)中,数组元素是存放在堆内存(heap)中,通过栈内存中的指针指向对应元素的在堆内存中的位置来实现访问,以下图来说明数组此时的存放形式。
栈内存存放的是方法的内部定义的变量,当方法执行完成后,栈内存也就随之消亡。而堆内存存放的一般是运行时的数据区以及创建一个对象的时候,对象是保存在堆内存,以便反复利用。当栈内存没用引用变量引用该数据区的数据时,垃圾回收就会合适时间来回收。
package com.eminem.vo; public class TestDemo { public static void main(String[] args) { int[] numbers = {3,4,5}; int[] digits = new int[4]; //把numbers的引用变量指向了digits的引用变量,此时的数组的长度就变成了3 digits = numbers; System.out.println(digits.length);//3 digits[3] = 6; System.out.println(digits.length);//java.lang.ArrayIndexOutOfBoundsException } }
digits的长度从4变成3,那是栈内存指向了堆内存数据等于3长读的数据。另外的4个数据就等待垃圾回收。
如果堆内存的数据元素也存放的是引用类型。此时数组元素存放引用,指向另外一快内存,在其中存放有效的数据。
package com.eminem.vo; class Person{ public int age; public String name; public void show(){ System.out.println(name+"的年龄:"+age); } } public class TestDemo { public static void main(String[] args) { //静态定义一个数组 Person[] persons; //分配内存空间 persons = new Person[2]; Person p1 = new Person(); p1.age=10; p1.name="zs"; Person p2 = new Person(); p2.age=20; p2.name="ls"; for (Person person : persons) { System.out.println(person);//null 由于还未给数组引用变量的null对象赋值 } persons[0] = p1; persons[1] = p2; for (Person person : persons) { person.show(); } } }
分析如下:
也就是栈内存存放了对堆内存的引用,堆内存的数组元素又引用了其他内存。
package com.eminem.vo; public class TestDemo { public static void main(String[] args) { //定义一个二维数组,一维是栈内存引用堆内存的数组元素, //二维是被栈引用的堆内存的数组元素的其中一个又去引用堆内存的其他数组元素 int [][] numbers; numbers = new int[3][];//静态初始化,长度为3的数组 for (int i =0;i<numbers.length;i++) { System.out.println(numbers[i]);//null } System.out.println("---------"); //栈内存引用堆内存的第一个数组元素又引用堆内存的其他数组元素 numbers[0] = new int[2]; //栈内存引用堆内存的第一个数组元素又引用堆内存的其他数组元素中的第二个元素1 numbers[0][0] = 1; numbers[0][1] = 2; for (int i = 0; i < numbers[0].length; i++) { System.out.println(numbers[0][i]); } System.out.println("---------"); numbers[2] = new int[3]; numbers[2][0] = 5; numbers[2][1] = 6; numbers[2][2] = 7; // numbers[2][3] = 8; // 由于第三个数组元素引用堆内存的其他数组元素的长度为3,超过了 java.lang.ArrayIndexOutOfBoundsException for (int i = 0; i < numbers[2].length; i++) { System.out.println(numbers[2][i]); } System.out.println("---------"); // numbers[3] = new int[1];// 由于numbers只定义了长度为3的数组元素 java.lang.ArrayIndexOutOfBoundsException } }
数组工具类:Arrays类
package com.eminem.vo; import java.util.Arrays; public class TestDemo { public static void main(String[] args) { int[] a = {3, 4, 5, 6}; int[] b = {3, 4, 5, 6}; //比较a与b是否相等 System.out.println(Arrays.equals(a, b)); //查找4在a的位置 System.out.println(Arrays.binarySearch(a, 4)); //1 //拷贝a到c,并设c长度为6 int[] c = Arrays.copyOf(a, 6); System.out.println(c.length); //6 //打印数组c System.out.println(Arrays.toString(c)); //[3, 4, 5, 6, 0, 0] //将a中的所有值赋值为1 Arrays.fill(a, 1); System.out.println(Arrays.toString(a));//[1, 1, 1, 1] //将c中的第三个到第五个赋值为2 Arrays.fill(c, 2, 5, 2); System.out.println(Arrays.toString(c));//[3, 4, 2, 2, 2, 0] //快速排序c Arrays.sort(c); System.out.println(Arrays.toString(c)); //[0, 2, 2, 2, 3, 4] } }
参考资料:
http://www.cnblogs.com/hmiinyu/archive/2012/10/22/2732781.html