前言
值傳遞和引用傳遞是java基礎(chǔ)知識中一個(gè)比較重要的概念,如果對這個(gè)概念理解不清的話,可能就會造成我們的代碼出現(xiàn)“對象中的值被無故改變了”這種問題。本篇文章將針對這兩個(gè)概念進(jìn)行介紹和講解,希望對各位讀者有所幫助。
(一)值傳遞的例子
我們先來看下面這個(gè)例子,判斷一下最終的輸出會是什么?
public class Test {
public static void main(String[] args) {
int i = 10;
changeValue(i);
System.out.println(i);
}
private static void changeValue(int i){
i = 20;
}
}
最終的執(zhí)行結(jié)果為10,這個(gè)結(jié)果似乎很好理解,調(diào)用changeValue方法時(shí),我們相當(dāng)于是將10作為入?yún)髁诉M(jìn)去,賦值給了changeValue方法的形參i,至于形參i后續(xù)的值發(fā)生變化,是不會影響到main方法中的i的。而上面例子中調(diào)用方法時(shí)只涉及到基本數(shù)據(jù)類型的傳遞,這種傳遞方式通常也被叫做值傳遞。

(二)引用傳遞的例子1
我們再來看下面這個(gè)例子,調(diào)用的方法入?yún)⒏某闪藢ο?,再來看看最終的輸出結(jié)果會是什么
public class Test {
String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public static void main(String[] args) {
Test test = new Test();
test.setName("aaa");
changeValue(test);
System.out.println(test.getName());
}
private static void changeValue(Test test){
test.setName("bbb");
}
}
最終的輸出結(jié)果如下,答案為bbb,可能會讓初學(xué)者感到不解,為何相似的操作得到的結(jié)果卻不同。我們在方法中修改了Test對象的屬性,為什么會影響到main方法中Test對象的值呢?

其實(shí)答案并不難理解,我們知道對于引用數(shù)據(jù)類型,這類對象的值并不會放在棧中,而是會單獨(dú)放在堆內(nèi)存中,而棧中對象的值為實(shí)際對象在堆內(nèi)存中的地址值(類似:0x123123123)。當(dāng)我們調(diào)用changeValue(Test test)方法時(shí),會將test對象在內(nèi)存中的引用傳遞了進(jìn)去。也就是說,此時(shí)main方法中的
test和changeValue方法中的形參test都指向了堆中的同一個(gè)對象。而changeValue方法在調(diào)用的過程中修改了對象在堆內(nèi)存中的屬性,main方法中的test變量也就會同樣受到影響。在這個(gè)例子中,我們傳遞給方法的參數(shù)是一個(gè)引用數(shù)據(jù)類型的變量,這種傳遞方式通常也被稱為引用傳遞。

(三)引用傳遞的例子2
我們再來看下面一個(gè)引用傳遞相關(guān)的例子,判斷一下最終輸出的值是什么
public class Test {
String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public static void main(String[] args) {
Test test = new Test();
test.setName("aaa");
changeValue(test);
System.out.println(test.getName());
}
private static void changeValue(Test test){
Test test1 = new Test();
test1.setName("bbb");
test = test1;
}
}
這次的執(zhí)行結(jié)果為aaa。原因也很好理解,changeValue方法中,我們只是對test形參的指向進(jìn)行了變化,并不涉及對原Test對象的修改。


值傳遞和引用傳遞的本質(zhì)
本質(zhì)上來說,所謂的引用傳遞實(shí)質(zhì)上也是值傳遞,只是傳遞的值是對象在內(nèi)存中的地址值而已。個(gè)人認(rèn)為,單純記傳入的值是基本數(shù)據(jù)類型還是引用類型并不是理解這個(gè)知識的好方法。更好的方法是理解調(diào)用方法傳入?yún)?shù)時(shí),代碼做了什么。以第二個(gè)例子為例,我們可以把執(zhí)行過程寫成下面的偽代碼:
(值傳遞的過程其實(shí)就只是一個(gè)簡單的值拷貝,然后賦值給方法的形參而已)
Test test = new Test();
test.setName("aaa");
//下面是changeValue(test)執(zhí)行的步驟
{
// 新建了一個(gè)Test類型的變量test1, 且把test的值賦給了變量test1
Test test1 = test;
// test的值本質(zhì)上就是一個(gè)地址值
test1.setName("bbb");
}
System.out.println(test.getName());
而原對象到底會不會被修改,最為關(guān)鍵的地方在于是否改動了原對象在內(nèi)存中的屬性值,形參單純的修改對象指向并不會對原對象造成影響。正因?yàn)閭鬟f對象時(shí)傳遞的是對象在內(nèi)存中的地址值,所以我們在進(jìn)行引用傳遞的時(shí)候,一定要注意,不要輕易修改原對象的屬性。如果涉及到修改的操作,建議深拷貝一份對象給形參之后,再進(jìn)行對象屬性的修改操作。
小結(jié)
至此,對于值傳遞和引用傳遞的概念就介紹到這里,深刻理解調(diào)用方法時(shí)的賦值過程,相信可以幫助各位初學(xué)者避開很多坑。