第一章:java基本功之数组与内存控制

数组与内存控制:

1.1数组初始化

java 语言的数组变量是引用类型的变量 。

1.1.1java数组是静态的

java是静态语言,java数组是静态的,即数组被初始化后数组的长度是不可变的,java程序中的数组必须经过初始化后才可以使用。初始化过程:为数组对象的元素分配内在空间,并为每个数组元素指定初始值。

数组初始化的两种方式:

静态初始化:初始化时由程序员显式指定每个数组元素的初始值,由系统决定数组长度。

动态初始化:初始化时程序员只指定数组长度,由系统为数组元素分配初始值。

不管用哪种初始化方式,java数组一旦初始化完成,该数组的长度就不可改变。

例:

package arrayAndMemoryControl;

public class ArrayTest {

	public static void main(String args[]){
		//采用静态初始化方式初始化第一个数组
		String [] books = new String[]{"深入理解JVM","深入理解操作系统","算法导论","java编程思想"};
		//采用静态初始化的简化形式初始化第二个数组
		String names[] = {"James","Rick","Jun"};
		//采用动态初始化的方式初始化第三个数组
		String []strArr = new String[5];
		
		//访问3个数组长度
		System.out.println("第一个数组长度:" + books.length);
		System.out.println("第二个数组长度:" + names.length);
		System.out.println("第三个数组长度:" + strArr.length);
	}
}

执行动态初始化时:

数组元素类型是整数类型(byte,short,int,long),则数组元素的值是0

数组元素类型是浮点类型(float,double),则数组元素的值是0.0

数组元素类型是字符类型(char),则数组元素的值是 '\u0000'

数组元素类型是布尔类型(boolean),则数组元素的值是false

数组元素类型是引用类型(类,接口,数组),则数组元素的值是null

注:改变一个数组变量所引用的数组,可以造成数组长度可变的假象。java的数组变量是一种引用类型的变量 ,数组变量并不是数组本身,它只是指向堆内存中的数组对象

例:

package arrayAndMemoryControl;

public class ArrayTest2 {
	public static void main(String args[]){
		//采用静态初始化方式初始化第一个数组
		String [] books = new String[]{"深入理解JVM","深入理解操作系统","算法导论","java编程思想"};
		//采用静态初始化的简化形式初始化第二个数组
		String names[] = {"James","Rick","Jun"};
		//采用动态初始化的方式初始化第三个数组
		String []strArr = new String[5];
		//让books数组变量和strArr数组变量指向names所引用的数组
		books = names;
		strArr = names;
		
		//访问3个数组长度
		System.out.println("books数组长度:" + books.length);
		System.out.println("strArr数组长度:" + strArr.length);
		//改变books数组变量所引用的数组的第二个元素值
		books[1] = "设计模式";
		System.out.println("names数组的第二个元素:" + books[1]);
	}
}


1.1.2注:Java的数组变量是引用类型的变量,它并不是数组对象本身,只要让数组变量指向有效的数组对象,程序中就可以使用该数组变量。

例:

package arrayAndMemoryControl;

public class ArrayTest3 {

	public static void main(String args[]){
		//定义并初始化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数组的第三个元素
		System.out.println("nums数组的第3个元素的值是:" + nums[2]);
		
	}
}


1.1.3 基本类型数组的初始化:程序直接先为数组分配内存空间,再将数组元素的值存入对应的内存里。

例:用静态初始化的方式初始化一个基本类型的数组对象

package arrayAndMemoryControl;

public class ArrayTest4 {
	public static void main(String args[]){
		//定义一个int[]类型的数组变量,这是一个引用类型变量,并未指向任何有效内存,
		int [] iArr; 
		//静态初始化数组,数组长度为4
		iArr = new int[]{2, 5, -12, 30};
	}
}

注: 如2,-5,23,33都是基本类型的值,都存储在堆内存中。所有局部变量都是放在栈内存里保存的,不管是基本类型的变量还是引用类型的变量 ,都是存储在各自的方法区栈中;但引用类型变量所引用的对象(包括数组和普通java对象)则总是存放在堆内存中。

堆内存中的对象通常不允许直接访问,为了访问堆的中对象,通常只通过引用变量。引用变量本质上只是一个指针,只要程序通过引用变量访问属性,或者通过引用变量调用方法,该引用变量将会由它所引用的对象代替。

例:

package arrayAndMemoryControl;

public class PrimitiveArrayTest {
	public static void main(String args[]){
		//定义一个int[] 类型的数组变量 
		int [] iArr = null;
		//只要不访问iArr的属性和方法,程序完全可以使用该数组变量 
		System.out.println(iArr);
		//动态初始化数组长度为5
		iArr = new int[5];//
		//只有当iArr指向有效的数组对象后,下面才可以访问iArr的属性,如果iArr未初始化,运行将报空指针错误
		System.out.println(iArr.length);
		//注:当通过引用变量访问实例属性或调用非静态方法时,如果该引用变量还未引用一个有效的对象,程序会出现NullPointerException运行时异常
	}
}


1.1.4引用类型数组的初始化

引用类型数组的数组元素依然是引用类型的,因此数组元素里存储的还是引用变量,它指向另一块内存,这块内存里存储了该引用变量所引用的对象(包括数组和java对象)

例:

package arrayAndMemoryControl;

class Person {
		
		public int age;//年龄
		
		public double height;//身高
		
		//定义一个info方法
		public void info(){
			System.out.println("年龄:" + age + ", 身高:" + height);
		}
}

public class ReferenceArrayTest{

	public static void main(String args[]){
		//定义一个students数组变量
		Person [] students;
		//执行动态初始化
		students = new Person[2];
		System.out.println("students所引用的数组长度是:" + students.length);
		//创建一个实例并将Person实例赋值给xie变量 
		Person xie = new Person();
		//为xie所引用的person对象的属性赋值
		xie.age = 12;
		xie.height = 200;
		
		//创建一个Person实例赋值给zhong
		Person zhong = new Person();
		//为zhong所引用的person对象的属性赋值
		zhong.age = 2;
		zhong.height = 201;
		//将xie变量的值赋给第一个数组元素
		students[0] = xie;
		//将zhong变量的值赋给第二个数组元素
		students[1] = zhong;
		//下面两行代码的结果完全一样,因为zhong和students[1]指向的是同一个 person实例
		zhong.info();
		students[1].info();
	}
}


1.2 使用数组

当数组引用变量指向一个有效数组对象后,程序可通过该数组引用变量来访问数组对象。java不允许直接访问堆内存中的数据,因此无法直接访问堆内在中的数组对象,程序将通过数组引用变量来访问数组。

1.2.1数组元素就是变量

例:数组元素和普通变量相互赋值
package arrayAndMemoryControl;

class Cat {
	double weight;
	int age;
	public Cat(double weight, int age){
		this.weight = weight;
		this.age = age;
	}
}

public class ArrayTest5 {
	public static void main(String args[]){
		//定义并动态初始化一个int[]数组
		int []pos = new int[5];
		//循环为每个元素赋值
		for(int i = 0; i < pos.length; i++){
			pos[i] = (i + 1) * 2;
		}
		//对于pos元素来说,用起来完全等同于普通变量
		//下面既可将数组元素的值赋给int变量,也可将int变量的值赋给数组元素
		int a = pos[1];
		int b = 20;
		pos[2] = b;
		//定义并动态初始化一个cat[]数组
		Cat[] cats = new Cat[2];
		cats[0] = new Cat(3.34, 2);
		cats[1] = new Cat(3.2, 2);
		//将cats数组的第一个元素值赋给c1
		Cat c1 = cats[0];
		Cat c2 = new Cat(4.3, 3);
		//将c2的值赋给cats数组的第二个元素
		cats[1] = c2;
	}
}

注:main方法声明的变量都属于局部变量,因此它们都被保存在main方法的栈中;但数组元素作为数组对象的一部分,总是保存在堆内存中,不管它们是基本类型的数组元素还是引用类型的数组元素。

1.2.2没有多维数组:N维数组是数组元素N-1维数组的数组,多维数组的本质是一维数组。

package arrayAndMemoryControl;

public class TwoDimensionTest {
	public static void main(String args[]){
		//定义一个2维数组
		int [][] a;
		//把a当成一维数组进行初始化为长度4的数组
		//a数组的数组元素又是引用类型
		a = new int[4][];
		//把a数组当成一维数组遍历a数组的每个元素
		for(int i = 0; i < a.length; i++){
			System.out.println(a[i]);
		}
		//初始化a数组的第一个元素
		a[0] = new int[2];
		//访问a数组的第一个元素所指数组的第2个元素
		a[0][1] = 6;
		//a数组的第一个元素是1个一维数组,遍历这个一维数组
		for(int i = 0; i < a[0].length; i++){
			System.out.println(a[0][i]);
		}
	}
}

如果定义一个Object[]类型的数组,每个数组元素都相当于一个Object类型的引用变量 ,因此可以指向任何对象(包括数组对象和普通java 对象),

例:极端程序理解数组在内存中的分配机制

package arrayAndMemoryControl;

public class ObjectArrayTest {
	public static void main(String args[]){
		//定义并初始化一个Object数组
		Object []objArr = new Object[3];
		//让objArr所引用数组的第2个元素再次指向一个长度为2的Object[]数组
		objArr[1] = new Object[2];
		//让objArr[2]和objArr[1]指向同一个数组对象
		Object[] objArr2 = (Object[])objArr[1];
		//让objArr2所引用数组的第2个元素再次指向一个长度为3的object[]数组
		objArr2[1] = new Object[3];
		//让objArr3和objArr2[1]指向同一个数组对象
		Object[] objArr3 = (Object[])objArr2[1];
		//让objArr2所引用的数组的第2个元素再次指向一个长度为5的int[]数组
		objArr3[1] = new int[5];
		//将objArr3[1]的值赋给iArr,即让iArr和objArr3[1]指向同一个数组对象
		int [] iArr = (int[])objArr3[1];
		//依次为iArr数组的每个元素赋值
		for(int i = 0; i < iArr.length; i++){
			iArr[i]= i * 3 + 1;
		}
		//直接通过objArr访问iArr数组的第三个元素
		System.out.println(((int[])((Object[])((Object[])objArr[1])[1])[1])[2]);
	}

}

总结:Java数组一旦初始化完成,该数组长度将不可改变。

你可能感兴趣的:(第一章:java基本功之数组与内存控制)