如題,在java中這是一個典型的問題。 在stackoverflow上已經有很多相似的問題被提問,並且有很多不正確或不完整的答案。如果你不往深處想,這是一個很簡單的問題。但如果深入思考,它卻很讓人迷惑。
1. 下面是一段很有意思並且讓人迷惑的代碼
public static void main(String[] args) { String x = new String("ab"); change(x); System.out.println(x); } public static void change(String x) { x = "cd"; }
運行它將打印 “ab”.
2. 通常讓人迷惑的解釋如下
在java堆中x存儲指向“ab”的引用。所以當x作為參數傳遞給change()方法時,它在內存中仍然指向“ab”,如下:
由於java是值傳遞,所以此時x仍然指向“ab”。當chang()方法執行時,它在內存中創建了一個新的String對象“cd”,並且現在x指向“cd”,如下:
上面的解釋看起來非常合理。他們也很清楚java是值傳遞。但是哪里出錯了?
3. 上面的代碼到底如何執行的呢?
上面的解釋有幾處錯誤。跟蹤代碼執行全過程是一個很好的方法,並且理解起來很容易。
當“ab”創建后,java分配對象所需內存空間。然后,變量x指向了“ab”,變量實際上是指向對象的引用。這個引用指向對象存儲的地址。
x保存了一個指向String對象的地址。x不是引用本身!它是保存一個內存地址。
在Java中只有值傳遞。當x通過參數傳遞給change()方法后,x被拷貝了一份。change()創建了另一個對象“cd”,並且x指向了不同的地址空間。實際上是x改變它的引用(指向“cd”),不是x本身。
下圖展示了x在內存的變化
4. 錯誤的解釋
上面的問題跟String的不可變沒有關系。即使是StringBuilder,結果也一樣。關鍵是變量存儲的是引用,而不是引用本身!他饒啦
5. 解決問題
如果真的要改變對象的值。首先,對象應該是可變的,如StringBuilder,另外,我們要確認沒有新對象生成並且賦予參數變量,因為java只有值傳遞
public static void main(String[] args) { StringBuilder x = new StringBuilder("ab"); change(x); System.out.println(x); } public static void change(StringBuilder x) { x.delete(0, 2).append("cd"); }