引用类型数组的数组元素是引用,因此情况变得更加复杂。每个数组元素里存储的还是引用,它指向另一块内存,这块内存里存储了
有效数据。
为了更好地说明引用类型数组的运行过程,下面先定义一个
Person类(所有类都是引用类型)。Person类的代码如下。
下 面 程 序 将 定 义 一 个 Person[] 数 组 , 接 着 动 态 初 始 化 这 个Person[]数组,并为这个数组的每个数组元素指定值。程序代码如下
上面代码的执行过程代表了引用类型数组初始化的典型过程。下面将结合示意图详细介绍这段代码的执行过程。
执行Person[] students;代码时,这行代码仅仅在栈内存中定义
了一个引用变量,也就是一个指针,这个指针并未指向任何有效的内
存区。此时内存中存储示意图如图所示。
在如上图所示的栈内存中定义了一个students变量,它仅仅是一
个引用,并未指向任何有效的内存。直到执行初始化,本程序对
students数组执行动态初始化,动态初始化由系统为数组元素分配默
认的初始值:null,即每个数组元素的值都是null。执行动态初始化
后的存储示意图如下图所示
从上图中可以看出,students数组的两个数组元素都是引用,而
且这个引用并未指向任何有效的内存,因此每个数组元素的值都是
null。这意味着依然不能直接使用students数组元素,因为每个数组
元素都是null,这相当于定义了两个连续的Person变量,但这个变量
还 未 指 向 任 何 有 效 的 内 存 区 , 所 以 这 两 个 连 续 的 Person 变 量
(students数组的数组元素)还不能使用。
接着的代码定义了zhang和lee两个Person实例,定义这两个实例
实际上分配了4块内存,在栈内存中存储了zhang和lee两个引用变量,
还在堆内存中存储了两个Person实例。此时的内存存储示意图如下图
所示。
此时students数组的两个数组元素依然是null,直到程序依次将zhang赋给students数组的第一个元素,把lee赋给students数组的第
二个元素,students数组的两个数组元素将会指向有效的内存区。此
时的内存存储示意图如下图所示。
从下图中可以看出,此时zhang和students[0]指向同一个内存
区,而且它们都是引用类型变量,因此通过zhang和students[0]来访
问 Person 实 例 的 实 例 变 量 和 方 法 的 效 果 完 全 一 样 , 不 论 修 改
students[0]所指向的Person实例的实例变量,还是修改zhang变量所
指向的Person实例的实例变量,所修改的其实是同一个内存区,所以
必然互相影响。同理,lee和students[1]也是引用同一个Person对
象,也具有相同的效果