1. 程式人生 > >JAVA中的值傳遞和引用傳遞問題

JAVA中的值傳遞和引用傳遞問題

log 輸出結果 基礎知識 blue static 繼續 oid .net red

  這是個老生常談的問題了,引起過無數爭論,但可以說一直沒有一個令人滿意的回答。

  有人總結過:

  1. 對象是按引用傳遞的
  2. Java 應用程序有且僅有的一種參數傳遞機制,即按值傳遞
  3. 按值傳遞意味著當將一個參數傳遞給一個函數時,函數接收的是原始值的一個副本
  4. 按引用傳遞意味著當將一個參數傳遞給一個函數時,函數接收的是原始值的內存地址,而不是值的副本

  簡單總結:

  1. 對象就是傳引用(引用地址的拷貝,實質也是傳值)
  2. 原始類型就是傳值
  3. String等immutable類型因為沒有提供自身修改的函數,每次操作都是新生成一個對象,所以要特殊對待。可以認為是傳值。

一個小問題

  在開源中國看到這樣一則問題:

https://www.oschina.net/question/2507499_2244027,其中的變量a前後的輸出是什麽?

  我答錯了,我認為傳入function的就是main函數中的a,在function中修改了a的地址,因此回到主函數後,a的地址已經變成了function中所賦予的a2的地址,因此經過function處理後a的值已經改變了。 但結果並不是,因為我忽略了Java的基礎知識點之一Java中傳參都是值傳遞,如果是基本類型,就是對值的拷貝,如果是對象,就是對引用地址的拷貝。

基本類型的傳遞

  以下是處理類Porcess,代碼應該已經能夠自解釋了。function1是將傳參a變成2,function2是初始化int b,賦值為5,然後將b賦值給a:

public class Process {

    public void function1(int a) {
        a = 2;
    }

    public void function2(int a) {
        int b = 5;
        a = b;
    }
}

我們繼續看測試類TestPrimitive:

public class TestPrimitive {

    public static void main(String[] args) {
        Process process 
= new Process(); int age = 18; System.out.println(age); process.function1(age); System.out.println(age); } }

經過function1處理後,結果是:

18
18

修改測試類,經過function2處理後,結果是:

18
18

結論:基本類型傳參,對傳參進行修改,不影響原本參數的值。

對象類型傳參

  以下是處理類Porcess,function3,將參數car的顏色設置成blue。function4,新建了car2,將car2賦值給了參數car。

public class Process {

    public void function3(Car car) {
        car.setColor("blue");
    }

    public void function4(Car car) {
        Car car2 = new Car("black");
        car = car2;
        car.setColor("orange");
    }
}

我們繼續看測試類TestReference

public class TestReference {

    public static void main(String[] args) {
        Process process = new Process();
        Car car = new Car("red");
        System.out.println(car);
        process.function3(car);
        System.out.println(car);
    }
}    

結果是在經過function3的處理後,輸出結果是:

Car{color=‘red‘}
Car{color=‘blue‘}

修改測試類,在經過function4的處理後:

Car{color=‘red‘}
Car{color=‘red‘}

結論: 對象類型的傳參,直接調用傳參set方法,可以對原本參數進行修改。如果修改傳參的指向地址,調用傳參的set方法,無法對原本參數的值進行修改。

綜上所述,基本類型的傳參,在方法內部是值拷貝,有一個新的局部變量得到這個值,對這個局部變量的修改不影響原來的參數。對象類型的傳參,傳遞的是堆上的地址,在方法內部是有一個新的局部變量得到引用地址的拷貝,對該局部變量的操作,影響的是同一塊地址,因此原本的參數也會受影響,反之,若修改局部變量的引用地址,則不會對原本的參數產生任何可能的影響。

JAVA中的值傳遞和引用傳遞問題