疯狂java读书笔记
java语言是典型的静态语言,因此java的数组是静态的。即当数组被初始化后,改数组的长度是不可变的。
java程序的数组必须经过初始化后才能使用。初始化是指:为数组对象的元素分配内存空间,并为每个元素指定初始值。
数组的初始化有两种:静态初始化、动态初始化
静态初始化:由程序员显示指定每个数组元素的值,由系统决定数组长度
例子:String[] books = new String[]{"疯狂java","hello kity"};
String[] name = {"river","sea"};
动态初始化:程序员指定数组长度,系统为数组元素分配初始值
例子:String[] strArr = new String[5];
系统分配初始值规定:
数组元素类型是基本类型中的整数类型(byte、short、int、long),则数组元素的值是0.
数组元素类型是基本类型中的浮点类型(float、double)则数组元素的值是0.0
数组元素类型是基本类型中的字符类型(char)则数组元素的值是‘\u0000’
数组元素类型是基本类型中的布尔类型(boolean),则数组元素的值是null
java数组是静态的,一旦为数组初始化完成,就无法改变数组的长度。
但是,需要指出的是,java的数组变量是一种引用型的变量,数组变量并不是数组本身。他只是指向堆内存中的数组对象。
因此,可以改变一个数组变量所引用的数组,这样可以造成数组长度可变的假象
对数组变量来说,他们并不需要进行所谓的初始化,只要让数组变量指向一个有效的数组对象,程序即可正常使用该数组变量。
需要初始化的永远只是该引用变量所引用的对象,而不是引用变量本身。
来看一个动态语言数组的例子,
javascript是一种动态语言,他的数组长度是可以动态改变的,程序如下:
var arr=[];
document.writeln("arr的长度是:"+arr.length+"");
arr[2] = 6;
arr[4] = "猴子";
document.writeln("arr的长度是:"+arr.length+"");
先:他不包含任何元素,长度是0,之后在第三个和第五个元素赋值,所以该数组长度自动变成5;
基本类型数组的初始化
对基本类型数组而言,数组元素的值直接存储在对应的数组元素上。
因此基本类型数组的初始化比较简单:程序直接先为数组分配内存空间,再将数组元素的值存入对应的内存中。
所有局部变量都是存放在栈内存中,不管其是基本类型的变量还是引用类型的变量,都是存储在各自的方法栈区中;但引用类型变量所引用的对象(包括数组、普通java对象)则总是存储在堆内存中。
问题:引用变量何时只是栈内存中的变量本身,何时又变为引用实际的java对象?
答:其实规则很简单,引用变量本质上只是一个指针,只要程序通过引用变量访问属性或方法,该引用变量将会由他所引用的对象代替。
如下代码所示:
//定义一个int[]类型的数组变量
int[] iArr = null
//只要不访问iArr的属性和方法,程序完全可以使用该数组变量
System.out.println(iArr);
//动态初始化数组
iArr = new int[5];
//只有当iArr指向有效的数组对象后,下面才可以访问iArr的属性
System.out.println(iArr.length);
引用类型数组的初始化
引用类型数组的数组元素依然是引用类型的,因此数组元素里存储的还是引用。他指向另一块内存,这块内存里存储了该变量所引用的对象(包括数组和java对象)。
对于引用类型的数组而言,他的数组元素其实是一个引用类型的变量,因此可以指向任何有效的内存——此处”有效“的意思是指强类型的约束。比如Person[]类型的数组,它的每个数组元素都相当于Person类型的变量,因此他的数组元素只能指向Person对象。
使用数组:
当数组引用变量指向一个有效的数组对象后,程序就可以通过该引用变量来访问数组对象。
java语言不允许直接访问堆内存中的数据,因此无法直接访问堆内存中的数组对象,程序将通过数组引用变量来访问数组。
一个极端的程序例子,方便理解数组在内存中的分配机制:
public class ObjectArrayTest {
public static void main(String[] args){
//定义并初始化一个Object数组
Object[] objArr = new Object[3];
//让objArr所引用数组的第二个元素再次指向一个长度为2的Object[]数组
objArr[1] = new Object[2];
//将objArr[1]的值赋给objArr2,即让objArr2和objArr[1]指向同一个数组对象
Object[] objArr2 = (Object[])objArr[1];
//让objArr2所引用的数组的第二个元素再次指向一个长度为3的Object[]数组
objArr2[1] = new Object[3];
//使objArr3和objArr2[1]指向同一个数组对象
Object[] objArr3 = (Object[])objArr2[1];
//让objArr2所引用的数组的第二个元素再次指向一个长度为5的int[]数组
objArr3[1] = new int[5];
//使iArr和objArr3[1]指向同一个数组对象
int[] iArr = (int[])objArr3[1];
//依次为iArr数组的每个元素赋值
for(int i=0;i
iArr[i] = i*3+1;
}
//程序最精彩的展示,直接通过objArr访问iArr数组的第三个元素
System.out.println(((int[])((Object[])((Object[])objArr[1])[1])[1])[2]);
}
}
阅读(4629) | 评论(11) | 转发(1) |