相信對很多初學java的人來說這個問題還是很重要,因爲不同於C,C++,java明確說明取消了指針,因爲指針往往是再帶來方便的同時也是導致代碼不安全的根源,而且還會使得程序變得非常複雜和難以理解。java放棄指針只是在java語言中沒有明確的指針定義,實質上,每一個new語句返回的都是一個指針的引用。只不過在大多數時候java不用關心如何操作這個“指針”,更不像在操作C++的指針那樣膽戰心驚,唯一要多注意的是在給函數傳遞對象的時候。所以,初學java的人不必花費太多精力去了解,但是對於一個真正的java程序員來說這個問題是基礎。廢話少說,直接進入正題:
java中是傳值還是傳引用呢 ?
關於這個問題,就像光到底是波還是粒子的問題一樣衆說紛紜。但是我們首先要搞清楚一點:不管java的參數類型是什麼,一律傳遞參數的副本(引用thinking in Java 中的一句話:When you're passing primitives into a method, you get a distinct copy of the primitive.When you're passing a reference into a method, you get a copy of the reference)。
java中的變量分爲以下兩類:
(1)基本類型變量(int,long,double,boolean,float, byte,char),對於這些變量,java傳遞的是值的副本(與c++相同),即把自己賦值一份傳遞,即使自己的副本變了,自己也不會改變;
(2)對象型變量。java傳遞的是引用的副本(複製指向地址的指針),而不是自己實際值的副本。爲啥這麼做呢?原因很簡單,因爲對象類型是放在堆裏邊的(new一個對象的時候實際上是再堆中開闢出了一塊內存空間存放對象,在棧中存放指向對象的指針),所以訪問位於堆中的對象相對於基本類型數據來說比較慢;另一方面是因爲對象類型本身就比較大,如果採用複製對象值的方法,不僅浪費內存而且速度比較慢。
在thinking in Java 中解釋是這樣的:不管是基本類型還是對象類型,都是傳值。這種說法是把引用的副本也看作了一種“值”,也能夠說的過去,但是本人還是更贊成將按值傳遞和按引用傳遞分開比較好理解。
注意:java中String類型也是對象型變量,所以它傳遞的是引用的副本。String是一個非可變類,其傳值還是傳引用顯得沒什麼區別。
理論說完了,下面看幾個例子:
num1:傳基本類型
public class Test {
public static void test(boolean test) {
test = !test;
System.out.println("In test(boolean):test = " + test);
}
public static void main(String args[]) {
boolean test = true;
System.out.println("Before test(boolean):test = " + test);
test(test);
System.out.println("After test(boolean):test = " + test);
}
}
運行結果:
Before test(boolean):test = true
In test(boolean):test = false //傳進去的是boolean類型的副本,副本改變了但是原值不改變
After test(boolean):test = true
num2:傳對象類型
public class Test {
public static void test(StringBuffer str) {
str.append(", World!");
}
public static void main(String args[]) {
StringBuffer string = new StringBuffer("Hello");
test(string);
System.out.println(string);
}
}
運行結果:Hello, World! //通過引用副本找到地址,然後修改裏邊的值,即修改了對象。
num3:關於傳String
public class Test {
public static void test(String str) {
str = "World";
}
public static void main(String args[]) {
String string = "Hello";
test(string);
System.out.println(string);
}
}
一眼看去輸出結果應該是:World
但是實際的運行結果卻是:Hello,String不是按引用傳遞的嗎?難道出問題了?
查了一下,原因如下:
執行str = “World”;這句的時候,系統會自動生成一個新的String對象,並把這個新對象的值設爲“World”,然後將這個對像的引用賦值給str,str是原來String的副本,改變的是副本的值,那麼就與原來的值沒有關係了。當test函數執行完畢,str隨之釋放,原來的內存地址上內容沒發生任何變化。因此輸出hello,num2中str.append(", World!");就不一樣了,StringBuffer是產生一塊內存空間,相關的增、刪、改操作都在其中進行,所以此句是在同一段內存上進行的,即修改了原值,str所指向的引用並沒有變。
水平有限,希望各位大神給予指正補充,Thank you!