java中按值傳遞和按引用傳遞問題

  相信對很多初學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!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章