Java改變引用數據類型的值


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。

圖解引用數據類型的值傳遞和內存變化

局部變量存儲在棧內存中,對象的值存儲在堆內存中,故進行初始化后,內存中的分布會呈現如下圖

PotPlayerMini64_Lj4JOGFnoF.png

此時棧內存中存儲了對象test、d1、d2的地址以及局部變量date的值,而堆內存中存儲了d1的值和d2的值,由棧內存中d1和d2的地址指向堆內存中各自的值。

而當執行了下面程序段后

        test.change1(date);
        /*
          省略中間的代碼
        */

    public void change1(int i){
    	/*
          尚未執行的代碼
        */
    }

此時內存如下圖所示

PotPlayerMini64_cI7fsNJcxJ.png

在方法change1中,程序段在棧內存中為形式參數i分配了新的空間,並通過值傳遞將其賦值為date的值,也就是9。

當開始執行代碼段

    public void change1(int i){
    	i = 1234;
    }

PotPlayerMini64_BOCqo5i6lq.png

形式參數i的值被改為1234,而date中的值並沒有改變。

當change1方法執行完畢后,為局部變量所分配的空間全部消失,而date的值依然為9,修改失敗。

PotPlayerMini64_Lj4JOGFnoF.png

繼續執行change2

        test.change2(d1);
        /*
          省略中間的代碼
        */

    public void change2(BirthDate b) {
    	/*
          尚未執行的代碼
        */
    }

此時內存如下圖所示

PotPlayerMini64_x5dlZKd9EM.png

系統在棧內存中開辟新的空間給b,並將對象d2的值(地址)傳遞給了形式參數對象b,使得b的地址指向了一個和d2地址指向相同的堆內存空間,也就是指向對象d2存儲的值。看起來就要修改成功了,不是嗎?

但當執行下面代碼段

    public void change2(BirthDate b) {
    	b = new BirthDate(22,2,2004);
    }

GmUsTgE52X.png

這時b的地址改為指向新new出來的對象,內容悄然發生改變。

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

PotPlayerMini64_Lj4JOGFnoF.png

最后看change3代碼段

        test.change3(d2);
        /*
          省略中間的代碼
        */

    public void change3(BirthDate b) {
    	/*
          尚未執行的代碼
        */
    }

PotPlayerMini64_x5dlZKd9EM.png

類似於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在堆內存中所指向的是同一塊內存空間,所以修改成功。

PotPlayerMini64_9uwcBvSpMm.png

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

PotPlayerMini64_OB4T6bSMh1.png


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM