Java改變引用數據類型的值
在Java中,引用數據類型的數據傳遞的是值(地址)的拷貝
對於以下代碼
class BirthDate {
private int day;
private int month;
private int year;
public BirthDate(int d, int m, int y) {
day = d;
month = m;
year = y;
}
public void setDay(int d) {
day = d;
}
public void setMonth(int m) {
month = m;
}
public void setYear(int y) {
year = y;
}
public int getDay() {
return day;
}
public int getMonth() {
return month;
}
public int getYear() {
return year;
}
public void display() {
System.out.println
(day + " - " + month + " - " + year);
}
}
public class Test {
public static void main(String args[]){
Test test = new Test();
int date = 9;
BirthDate d1= new BirthDate(7,7,1970);
BirthDate d2= new BirthDate(1,1,2000);
test.change1(date);
test.change2(d1);
test.change3(d2);
System.out.println("date=" + date);
d1.display();
d2.display();
}
public void change1(int i){
i = 1234;
}
public void change2(BirthDate b) {
b = new BirthDate(22,2,2004);
}
public void change3(BirthDate b) {
b.setDay(22);
}
}
上述是一個對生日對象進行初始化,並進行修改的程序。程序通過構造函數進行初始化,並嘗試使用不同方法對對象存儲的值進行修改。
Birthdate是一個引用數據類型,簡單地用方法傳遞值不能改變對象存儲的值,應該使用類Birthdate的特定方法setDay。
圖解引用數據類型的值傳遞和內存變化
局部變量存儲在棧內存中,對象的值存儲在堆內存中,故進行初始化后,內存中的分布會呈現如下圖

此時棧內存中存儲了對象test、d1、d2的地址以及局部變量date的值,而堆內存中存儲了d1的值和d2的值,由棧內存中d1和d2的地址指向堆內存中各自的值。
而當執行了下面程序段后
test.change1(date);
/*
省略中間的代碼
*/
public void change1(int i){
/*
尚未執行的代碼
*/
}
此時內存如下圖所示

在方法change1中,程序段在棧內存中為形式參數i分配了新的空間,並通過值傳遞將其賦值為date的值,也就是9。
當開始執行代碼段
public void change1(int i){
i = 1234;
}

形式參數i的值被改為1234,而date中的值並沒有改變。
當change1方法執行完畢后,為局部變量所分配的空間全部消失,而date的值依然為9,修改失敗。

繼續執行change2
test.change2(d1);
/*
省略中間的代碼
*/
public void change2(BirthDate b) {
/*
尚未執行的代碼
*/
}
此時內存如下圖所示

系統在棧內存中開辟新的空間給b,並將對象d2的值(地址)傳遞給了形式參數對象b,使得b的地址指向了一個和d2地址指向相同的堆內存空間,也就是指向對象d2存儲的值。看起來就要修改成功了,不是嗎?
但當執行下面代碼段
public void change2(BirthDate b) {
b = new BirthDate(22,2,2004);
}

這時b的地址改為指向新new出來的對象,內容悄然發生改變。
當change2方法執行完畢后,為局部變量所分配的空間全部消失,存儲在堆內存中的值也會在一段時間后被垃圾回收機制回收,而d2的值並沒有發生變化,修改依然失敗。

最后看change3代碼段
test.change3(d2);
/*
省略中間的代碼
*/
public void change3(BirthDate b) {
/*
尚未執行的代碼
*/
}

類似於change2,系統給形式參數b分配了空間,指向d2對象的值
接下來執行setDay方法
public void setDay(int d) {
day = d;
}
/*
省略中間的代碼
*/
public void change3(BirthDate b) {
b.setDay(22);
}
setDay是類Birthdate中的方法,調用setDay方法后,會將setDay(int d)中的形式參數d傳遞給day這個成員變量,反映在內存中就是b的屬性day變為22,由於b和d2在堆內存中所指向的是同一塊內存空間,所以修改成功。

最后b這塊內存消失,此時Birthdate對象d2的值已經發生改變。

