天天看點

java按值傳遞基本資料類型,按引用傳遞對象

在閱讀本文之前,根據自己的經驗和了解,大家可以先思考并選擇一下java函數的參數傳遞方式: 

a. 是按值傳遞的? 

b. 按引用傳遞的? 

c. 部分按值部分按引用? 

此處暫不宣布正确答案,我們通過一個簡單的例子讓大家自己找答案: 

1. 先定義一個類型value 

java代碼  

public static class value {  

    private string value = "value";  

    public string getvalue() { return value; }  

    public void setvalue(string value) { this.value = value; }  

}  

2. 寫兩個函數newvalue和modifyvalue:newvalue會将入參指向一個新的對象,modifyvalue會調用入參的setvalue方法修改對象的value值。 

public static void newvalue(value value) {  

    value = new value();  

    value.setvalue("new value");  

    system.out.println("in newvalue, hashcode = " + value.hashcode() + ", value = " + value.getvalue());  

public static void modifyvalue(value value) {  

    system.out.println("in modifyvalue, hashcode = " + value.hashcode() + ", value = " + value.getvalue());  

3. 簡單的測試代碼 

public static void main(string[] args) {  

    value value1 = new value();  

    system.out.println("before modify, hashcode = " + value1.hashcode() + ", value = " + value1.getvalue());  

    // 将value1指向新的value對象  

    newvalue(value1);  

    system.out.println("after modify, hashcode = " + value1.hashcode() + ", value = " + value1.getvalue() + "\n");  

    value value2 = new value();  

    system.out.println("before modify, hashcode = " + value2.hashcode() + ", value = " + value2.getvalue());  

    // 使用object的set方法,修改對象的内部值  

    modifyvalue(value2);  

    system.out.println("after modify, hashcode = " + value2.hashcode() + ", value = " + value2.getvalue());  

4. 執行結果日志: 

before modify, hashcode = 12677476, value = value  

in newvalue, hashcode = 33263331, value = new value  

after modify, hashcode = 12677476, value = value  

before modify, hashcode = 6413875, value = value  

in modifyvalue, hashcode = 6413875, value = new value  

after modify, hashcode = 6413875, value = new value  

5. 結果分析: 

上述代碼這是非常常見的一種程式設計模式:在外圍定義|儲存|擷取一個值或對象,将這個對象作為參數傳入一個方法,在方法中修改對象的屬性、行為。但兩個方法newvalue和modifyvalue的修改方式不一樣,在方法調用之後,該對象在外圍看來也有很大的差别!如何了解這種差異呢?先溫故一下按值傳遞、按引用傳遞的概念: 

* 按值傳遞意味着當将一個參數傳遞給一個函數時,函數接收的是原始值的一個副本。是以,如果函數修改了該參數,僅改變副本,而原始值保持不變。 

* 按引用傳遞意味着當将一個參數傳遞給一個函數時,函數接收的是原始值的記憶體位址,而不是值的副本。是以,如果函數修改了該參數,參數的原始值(函數塊之外的調用代碼中)也随之改變。 

正确的答案:a——java函數是按值傳遞參數的! 

分析一下日志: 

* 第一段日志輸出,value1參數在newvalue方法内部被改為指向新對象,并輸出了新對象的hashcode和value值,但跳出newvalue方法域之後,在main方法中的value1沒有發生任何變化,這符合按值傳遞的定義和特點;如果是按引用傳遞,value1在調用newvalue(value value)方法之後,應該是發生變化的。 

* 第二段日志輸出,value2在modifyvalue方法内部進行了setvalue操作,hashcode不變而value被修改,離開modifyvalue方法域之後,在main方法中value2确實發生了變更。使用過c++的人容易将這種現象了解為:按引用傳遞函數參數!因為這跟c++中的按引用傳遞像極了!但這裡恰恰是最容易陷入誤區的地方! 

兩段日志的不同現象背後所隐藏的是原理是:java語言是按值傳遞參數,按引用傳遞對象的;java中所操作的對象其實都是操作對象的引用,object本身儲存在“堆”中,而對象的“引用“儲存在寄存器或“棧”中。 

僞代碼描述一下newvalue方法和modifyvalue方法的不同之處: 

newvalue{  

    value_ref2 = value_ref1;    // 按值傳入引用value_ref1,得到value_ref1的副本  

    value_obj2 = new value();   // value_obj2被建立、初始化在“堆“中  

    value_ref2 -> value_obj2;    // value_ref2 指向value_obj2  

value_ref2 ->value_obj2.setvalue(“xxx”); // value_obj2 的value被修改  

printvalueobj2();           // 此處列印的是obj2的值  

modifyvalue{  

value_ref2 ->value_obj1.setvalue(“xxx”); // value_obj1 的value被修改  

printvalueobj1();           // 此處列印的是obj1的值  

夠清楚了吧!value1_ref1在作為參數傳入函數的時候,首先被複制了一份副本value1_ref2供函數域使用,此時這兩個ref都是指向同一個value_obj; newobject函數中的代碼[ value = new value(); ] 其實是将value1_ref1指向了一個新的對象value_obj2;在這之後的set操作都是對新對象的操作;modifyvalue函數是通過set方法直接操作value_obj1,這是跟newvalue函數的不同之處。