1. 程式人生 > >Java 中引用傳遞還是值傳遞

Java 中引用傳遞還是值傳遞

【一:搞清楚 基本型別 和 引用型別的不同之處】

int num = 10;
String str = "hello";

這裡寫圖片描述
如圖所示,num是基本型別,值就直接儲存在變數中。而str是引用型別,變數中儲存的只是實際物件的地址。一般稱這種變數為”引用”,引用指向實際物件,實際物件中儲存著內容。
【二:搞清楚賦值運算子(=)的作用】

num = 20;
str = "java";

這裡寫圖片描述

對於基本型別 num ,賦值運算子會直接改變變數的值,原來的值被覆蓋掉。對於引用型別 str,賦值運算子會改變引用中所儲存的地址,原來的地址被覆蓋掉。但是原來的物件不會被改變(重要)。如上圖所示,”hello” 字串物件沒有被改變。(沒有被任何引用所指向的物件是垃圾,會被垃圾回收器回收)

【三:呼叫方法時發生了什麼?引數傳遞基本上就是賦值操作。】

//第一個例子:基本型別
void foo(int value) {
    value = 100;
}
foo(num); // num 沒有被改變

//第二個例子:沒有提供改變自身方法的引用型別
void foo(String text) {
    text = "windows";
}
foo(str); // str 也沒有被改變

//第三個例子:提供了改變自身方法的引用型別
StringBuilder sb = new StringBuilder("iphone");
void foo(StringBuilder builder) {
    builder.append("4"
); } foo(sb); // sb 被改變了,變成了"iphone4"。 //第四個例子:提供了改變自身方法的引用型別,但是不使用,而是使用賦值運算子。 StringBuilder sb = new StringBuilder("iphone"); void foo(StringBuilder builder) { builder = new StringBuilder("ipad"); } foo(sb); // sb 沒有被改變,還是 "iphone"。

重點理解為什麼,第三個例子和第四個例子結果不同?
下面是第三個例子的圖解:
這裡寫圖片描述
builder.append(“4”)之後
這裡寫圖片描述

下面是第四個例子的圖解:
這裡寫圖片描述


builder = new StringBuilder(“ipad”); 之後
這裡寫圖片描述

  1. = 是賦值操作(任何包含=的如+=、-=、 /=等等,都內含了賦值操作)。不再是你以前理解的數學含義了,而+ - * /和 = 在java中更不是一個級別,換句話說, = 是一個動作,一個可以改變記憶體狀態的操作,一個可以改變變數的符號,而+ - * /卻不會。這裡的賦值操作其實是包含了兩個意思:1、放棄了原有的值或引用;2、得到了 = 右側變數的值或引用。Java中對 = 的理解很重要啊!!可惜好多人忽略了,或者理解了卻沒深思過。
  2. 對於基本資料型別變數,= 操作是完整地複製了變數的值。換句話說,“=之後,你我已無關聯”;至於基本資料型別,就不在這科普了。
  3. 對於非基本資料型別變數,= 操作是複製了變數的引用。換句話說,“嘿,= 左側的變數,你丫別給我瞎動!咱倆現在是一根繩上的螞蚱,除非你再被 = 一次,放棄現有的引用!!上面說了 = 是一個動作,所以我把 = 當作動詞用啦!!”。
  4. 引數本身是變數,引數傳遞本質就是一種 = 操作。引數是變數,所有我們對變數的操作、變數能有的行為,引數都有。所以把C語言裡引數是傳值啊、傳指標啊的那套理論全忘掉,引數傳遞就是 = 操作。

Java只有一種引數傳遞方式:那就是按值傳遞,即Java中傳遞任何東西都是傳值
如果引數是基本型別,傳遞的是基本型別的字面量值的拷貝。
如果引數是引用型別,傳遞的是該參量所引用的物件在堆中地址值的拷貝