值傳遞OR引用傳遞?大部人都答錯了!
Java 是值傳遞還是引用傳遞?這是 Java 中比較基礎(chǔ)的一道常見面試題,但對于這道問題的大部分答案都是錯的,大部人會這樣回答這個問題:
在 Java 中,如果傳遞的是基本數(shù)據(jù)類型,那么就是值傳遞;而如果傳遞的是對象或數(shù)組的話,那么就是引用傳遞。
然而,這個答案是錯的!
定義描述
值傳遞和引用傳遞是編程中參數(shù)傳遞給方法時的兩種方式,它們的定義如下:
- 值傳遞(Pass by Value):在值傳遞中,實際參數(shù)的值被復(fù)制一份,然后將這份復(fù)制的值傳遞給函數(shù)或方法的相應(yīng)參數(shù)。因此,函數(shù)或方法內(nèi)對參數(shù)所做的任何修改都不會影響到實際參數(shù)的值。
- 引用傳遞(Pass by Reference):在引用傳遞中,傳遞給方法的是實際參數(shù)的引用(或地址)。這意味著方法內(nèi)對參數(shù)所做的任何修改都會直接影響到實際參數(shù)。
需要注意的是,有些編程語言,如 C++ 提供了真正的引用傳遞機制,允許你直接傳遞變量的引用,并且可以在函數(shù)或方法中改變這個引用的指向。而在 Java 中,即使是對象,也是通過值傳遞的,只不過這個值是對象引用副本(而非對象引用本身)。
正確結(jié)論
在 Java 中,(傳遞參數(shù)時)無論是基本數(shù)據(jù)類型還是對象(或數(shù)組),使用的都是值傳遞的方式。只是對于對象(或數(shù)組)而言,傳遞的值是對象引用副本,而非對象引用本身。
在 Java 中,只有值傳遞沒有引用傳遞。
舉個例子
例如 Integer 是包裝類對象吧?它不是基本數(shù)據(jù)類型對吧,當我們傳遞 Integer 對象時,在新方法所做的所有修改,并不會影響原對象本身,具體示例代碼如下:
public class PassExample {
public static void main(String[] args) {
Integer number = new Integer(10);
method(number);
System.out.println("number:" + number); // 輸出:number:10
}
public static void method(Integer number) {
number = 20; // 修改 num 的值,不會影響原始變量的值
}
}
以上程序的執(zhí)行結(jié)果如下:
圖片
“
從上述結(jié)果可以看出,當傳遞的是 Integer 對象時,其依然是值傳遞,所以在 Java 語言中,并沒有引用傳遞。
因此,無論是基礎(chǔ)數(shù)據(jù)類型,還是引用數(shù)據(jù)類型(對象),都為值傳遞,而非引用傳遞。
特殊的例子
有人說:不對啊,磊哥,你看我傳遞數(shù)組時,改變傳遞的數(shù)組就會影響原數(shù)組啊,具體示例如下:
public class PassExample {
public static void main(String[] args) {
char[] name = {'磊', '哥'};
System.out.println("調(diào)用方法前:" + new String(name));
method(name);
System.out.println("調(diào)用方法后:" + new String(name));
}
private static void method(char[] n) {
n[1] = '神';
System.out.println("方法中修改為:" + new String(n));
}
}
以上程序的執(zhí)行結(jié)果為:
調(diào)用方法前:磊哥
方法中修改為:磊神
調(diào)用方法后:磊神
這樣就出問題了,當傳遞了數(shù)組之后,明顯是“引用傳遞”,而非值傳遞,這到底是怎么回事?
別著急,當我們把新方法中的代碼做了以下調(diào)整之后,運行結(jié)果又不一樣了,如下代碼所示:
public class PassExample {
public static void main(String[] args) {
char[] name = {'磊', '哥'};
System.out.println("調(diào)用方法前:" + new String(name));
method(name);
System.out.println("調(diào)用方法后:" + new String(name));
}
private static void method(char[] n) {
n = new char[2]; // 僅僅添加了此行代碼
n[1] = '神';
System.out.println("方法中修改為:" + new String(n));
}
}
以上程序的執(zhí)行結(jié)果為:
調(diào)用方法前:磊哥
方法中修改為: 神
調(diào)用方法后:磊哥
你會發(fā)現(xiàn),當我們在新方法中僅僅添加了一行“n = new char[2];”代碼時,它又變成了值傳遞,這是怎么回事?
原因分析
如果是引用傳遞,那么我在新方法中無論如何修改,那么都應(yīng)該是影響原對象才對,而剛才我稍微調(diào)整了代碼之后就發(fā)現(xiàn)其并非引用傳遞,而是值傳遞,這是因為當傳遞數(shù)組時,其傳遞的是“引用副本”,而非真正的引用對象(也就是其本身)。
也就說,當傳遞數(shù)組時,其實傳遞的是“引用副本”,如下圖所示:
圖片
然而,在調(diào)用了“n = new char[2];”代碼之后,給變量在堆上創(chuàng)建了新對象,此時就不再使用原來的引用副本了,這個時候,再修改新方法中的變量就不影響原變量了,如下圖所示:
圖片
所以,在 Java 中,只有值傳遞,它始終傳遞的都是副本,而非原(引用)對象。
小結(jié)
在 Java 中,(傳遞參數(shù)時)無論是基本數(shù)據(jù)類型還是對象(或數(shù)組),使用的都是值傳遞的方式。只是對于對象(或數(shù)組)而言,傳遞的值是對象引用副本,而非對象引用本身。