參考型別數組的數組元素是引用,因此情況變得更加複雜:每個數組元素裡儲存還是引用,它指向另一塊記憶體,這塊記憶體裡儲存了有效資料。
為了更好地說明參考型別數組的運行過程,下面先定義一個Person類(所有類都是參考型別),關於定義類、對象和引用的詳細介紹請參考第5章的介紹。Person類的代碼如下:
程式清單:codes/04/4-6/Person.javapublic class Person{//年齡public int age;//身高public double height;//定義一個info方法public void info(){System.out.println("我的年齡是:" + age + ",我的身高是:" + height);}}
下面程式將定義一個Person[]數組,接著動態初始化這個Person[]數組,並為這個數組的每個數組元素指定值。程式碼如下:
程式清單:codes/04/4-6/TestReferenceArray.javapublic class TestReferenceArray{public static void main(String[] args) {//定義一個students陣列變數,其類型是Person[]Person[] students;//執行動態初始化students = new Person[2];//建立一個Person執行個體,並將這個Person執行個體賦給zhang變數Person zhang = new Person();//為zhang所引用的Person對象的屬性賦值zhang.age = 15;zhang.height = 158;//建立一個Person執行個體,並將這個Person執行個體賦給lee變數Person lee = new Person();//為lee所引用的Person對象的屬性賦值lee.age = 16;lee.height = 161;//將zhang變數的值賦給第一個數組元素students[0] = zhang;//將lee變數的值賦給第二個數組元素students[1] = lee;//下面兩行代碼的結果完全一樣,因為lee和students[1]指向的是同一個Person執行個體。lee.info();students[1].info();}}
上面代碼的執行過程代表了參考型別數組的初始化的典型過程,下面將結合詳細介紹這段代碼的執行過程。
執行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對象,也有相同的效果。