String是值傳遞還是引用傳遞


本文來自慕課網文章:https://www.imooc.com/article/288336

今天發現了一個比較有意思的問題。把一個String類型的參數傳入方法,並在方法內改變了引用的值。
然后在方法外使用這個值,發現這個String還是之前的值,並沒有改變。

這里要向大家介紹一下,大家都知道java在傳參時分為值 傳遞 和 引用傳遞 。參數為基本類型時是值傳遞,
參數為封裝類型時是引用傳遞。例如:

基本類型參數

 1 public class Test {
 2     public static void main(String[] args) {
 3         int num = 0 ;
 4         changeNum(num);
 5         System.out.println("num="+num);
 6     }
 7 
 8     private static void changeNum(int num) {
 9         num = 1;
10     }
11 }

打印的結果是num=0

封裝類型參數

 

 1 public class Test {
 2     public static void main(String[] args) {
 3         Product p = new Product();
 4         p.setProName("before");
 5         p.setNum(0);
 6         changeProduct(p);
 7         System.out.println("p.proName="+p.getProName());
 8         System.out.println("p.num="+p.getNum());
 9     }
10 
11     private static void changeProduct(Product p) {
12         p.setProName("after");
13         p.setNum(1);
14     }
15 }
16 
17 class Product {
18     private int num;
19     private String proName;
20 
21     public int getNum() {
22         return num;
23     }
24 
25     public void setNum(int num) {
26         this.num = num;
27     }
28 
29     public String getProName() {
30         return proName;
31     }
32 
33     public void setProName(String proName) {
34         this.proName = proName;
35     }
36 }

運行的結果是:p.proName=afterp.num=1 。

上面的兩個例子是明顯的值傳遞和引用傳遞。但是如果參數是String類型呢?我們看一下具體的例子

 

public class Test { public static void main(String[] args) { String str = "ab"; changeString(str); System.out.println("str="+str); } private static void changeString(String str) { str = "cd"; } }

大家猜一下運行結果是什么呢?按照前面的例子,String應該是一個封裝類型,它應該是引用傳遞,是可以改變值得,
運行的結果應該是"cd"。我們實際運行一下看看,

str=ab,這如何解釋呢?難道String是基本類型?也說不通呀。

這就要從java底層的機制講起了,java的內存模型分為 堆 和 棧 。

1.基本類型的變量放在棧里;
2.封裝類型中,對象放在堆里,對象的引用放在棧里。

java在方法傳遞參數時,是將變量復制一份,然后傳入方法體去執行。 這句話是很難理解的,也是解釋這個
問題的精髓。我們先按照這句話解釋一下基本類型的傳遞

問題的精髓。我們先按照這句話解釋一下基本類型的傳遞

  1. 虛擬機分配給num一個內存地址,並且存了一個值0.
  2. 虛擬機復制了一個num,我們叫他num’,num’和num的內存地址不同,但存的值都是0。
  3. 虛擬機講num’傳入方法,方法將num’的值改為1.
  4. 方法結束,方法外打印num的值,由於num內存中的值沒有改變,還是0,所以打印是0.

我們再解釋封裝類型的傳遞:

  1. 虛擬機在堆中開辟了一個Product的內存空間,內存中包含proName和num。
  2. 虛擬機在棧中分配給p一個內存地址,這個地址中存的是1中的Product的內存地址。
  3. 虛擬機復制了一個p,我們叫他p’,p和p’的內存地址不同,但它們存的值是相同的,都是1中Product的內存地址。
  4. 將p’傳入方法,方法改變了1中的proName和num。
  5. 方法結束,方法外打印p中變量的值,由於p和p’中存的都是1中Product的地址,但是1中Product里的值發生了改變,
    所以,方法外打印p的值,是方法執行以后的。我們看到的效果是封裝類型的值是改變的。

最后我們再來解釋String在傳遞過程中的步驟:

  1. 虛擬機在堆中開辟一塊內存,並存值"ab"。
  2. 虛擬機在棧中分配給str一個內存,內存中存的是1中的地址。
  3. 虛擬機復制一份str,我們叫str’,str和str’內存不同,但存的值都是1的地址。
  4. 將str’傳入方法體
  5. 方法體在堆中開辟一塊內存,並存值"cd"
  6. 方法體將str’的值改變,存入5的內存地址
  7. 方法結束,方法外打印str,由於str存的是1的地址,所有打印結果是"ab"

這樣我們理解了java在方法傳參的整個過程。其實還是上面那句比較重要的話 java在方法傳遞參數時,是將變量復制一份,然后傳入方法體去執行。

 




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM