天天看点

java疯狂讲义(一.数组)

初始化数组的两种方式

1.静态初始化:初始化时指定每个元素的值

2.动态初始化:初始化时指定数组的长度

java数组变量是一种引用类型的变量

数组元素和数组变量在内存里是分开的。 实际的数组元素被存储在堆(heap)内存中;数组引用变量是一个引用类型的变量,被存储在栈(stack)内存中。 当一个方法执行时,每个方法都会建立自己的内存栈,在这个方法内定义的变量将会逐个放入这块栈内存里,随着方法的执行结束,这个方法的内存栈随之销毁。因此,所有在方法中定义的变量都是放在栈内存中的;当我们在程序中创建一个对象时,这个对象将被保存在运行时数据区中,以便反复利用(因为对象的创建成本通常较大),这个运行时数据区就是堆内存。堆内存的独享不会随方法的结束而销毁,即使方法结束后,这个对象还可能被另一个引用变量引用,则这个对象依然不会被销毁。只有当一个对象没有任何引用变量引用它时,系统的垃圾回收机制才会在合适的时候回收它。

1.基本类型数组的初始化

当程序定义并初始化了a、b两个数组时,系统内存中实际产生了4块内存区,其中栈内存中有两个引用变量:a和b;堆内存中也有两块内存区,分别用于存储a和b引用所指向的数组本身。 内存的存储示意图如下图所示:
java疯狂讲义(一.数组)

当b=a代码时,系统将会把a的值赋给b,a和b都是引用类型变量,存储的是地址。因此把a的值赋给b后,就是让b指向a所指向的地址。此时计算机内存的存储示意图如下所示:

java疯狂讲义(一.数组)

当执行了b=a之后,堆内存中第一个数组中具有了两个引用:a变量和b便来那个都指向了第一个数组。

此时第二个数组失去了作用,变成垃圾,只有等待垃圾回收来回收它——但它的长度依然不会改变,直到它彻底消失。

2.引用类型数组的初始化

引用类型数组的数组元素是引用:每个数组元素里存储还是引用,它指向另一块内存,这块内存里存储了有效数据。

//定义一个students数组变量,其类型是Person[] Person[] students;   // 这行代码仅仅在栈内存中定义了一个引用变量,也就是一个指针,这个指针并未指向任何有效的内存区。此时内存中存储示意图如下所示:

java疯狂讲义(一.数组)

//执行动态初始化 students =new Person[2]; //

java疯狂讲义(一.数组)

//创建一个Person示例,并将这个Person示例赋给zhang变量 Person zhang=new Person(); //为zhang所引用的Person对象的属性赋值 zhang.age=15; zhang.height=158; //创建一个Person示例,并将这个Person实例赋值给lee变量 Perosn lee=new Person(); //为lee所引用的Person对象的属性赋值 lee.age=16; lee.height=161; //定义两个Person实例,定义这两个实例实际上分配了4块内存,在栈内存中存储了zhang和lee两个引用变量,还在堆内存中存储了两个Person实例。此时的内存存储示意图如下所示:

java疯狂讲义(一.数组)

//将zhang变量的值赋给第一个数组元素 students[0]=zhang; //将lee变量的值赋给第二个数组元素 students[1]=lee; //当程序把张赋给students数组的第一个元素,把lee赋给students数组的第二个元素,students数组的两个数组元素将会指向有效的内存区。此时的内存存储示意图如下所示:

java疯狂讲义(一.数组)

从上面图可以看出:此时zhang和students[0]指向同一个内存区,而且它们都是引用类型变量,因此通过zhang和student[0]来访问Person实例的属性和方法的效果完全一样,不论修改students[0]所指向的Person实例的属性,还是修改zhang变量所指向的Person实例的属性,所修改的其实是同一个内存区,所以必然互相影响。同理,lee和students[1]也有相同的效果。