Java 與值傳遞

問: 什麼是值傳遞?什麼是引用傳遞?爲何說 Java 中只有值傳遞?java


1、值傳遞與引用傳遞

實參與形參:函數

  • 實際參數:在調用有參函數時,主調函數和被調函數之間有數據傳遞關係。在主調函數中調用被調函數時,函數名後面括號中的參數稱爲「實際參數」。
  • 形式參數:在定義函數名和函數體時使用的參數,目的是用來接收調用此函數時傳入的參數。

值傳遞與引用傳遞:post

  • 值傳遞:是指在調用函數時,將實際參數複製一份,經過形參傳遞到函數中。這時形參接收到的內容是實參的一個副本,這樣在函數中若是對形參進行修改,不會影響到實際參數。
  • 引用傳遞:是指在調用函數時,將實際參數的地址傳遞到函數中,那麼在函數中對參數進行的修改,將會影響到實際參數。

重點的區別在於:測試

方面 值傳遞 引用傳遞
根本區別: 會建立副本(copy) 不會建立副本
因此: 函數中沒法改變原始對象 函數中能夠改變原始對象

2、Java 中的值傳遞

這裏須要清楚 JVM 內存的劃分及職能,即:線程

  1. 虛擬機棧
  2. 程序計數器
  3. 方法區
  4. 本地方法棧

已知,JVM 會給每一個線程分配一個 Java 棧,當執行一個方法時,JVM 會往該棧中壓入一個棧幀。code

1. 對於基本數據類型

在方法中,基本數據類型的形參及變量(稱爲局部變量)的名字和值都存儲於棧中。在該方法被調用時,會爲形參在棧幀中開闢一塊內存,將實參值複製給形參,而後形參和實參之間便沒有了關聯。對象

即,此後在方法中對形參的操做不會影響到原來的實參。 例:內存

public static void main(String[] args) {
    int a = 21;
    intTest(a);
    System.out.println("方法執行後的a: "+a);
}

public static void intTest(int var){
    // 將實參值複製給形參
    System.out.println("傳入的形參var:"+var);
    
    // 在方法中對形參的操做不會影響到原來的實參
    var = 23;
    System.out.println("方法內從新賦值後的形參var:"+var);
}

運行結果:get

傳入的形參var:21
方法內從新賦值後的形參var:23
方法執行後的a: 21

2. 對於引用數據類型(對象類型)

Java 裏面的變量,要麼是基本數據類型,要麼是指向對象實例的引用類型,絕對不會是一個對象。虛擬機

對於引用數據類型的對象,變量的名和值均存儲在棧中,變量值存儲的是對象的地址,對象的實際內容存儲於堆(堆區是共享的)中。在該方法被調用時,會爲形參在棧幀中開闢一塊內存,將實參值複製給形參,即把實參指向的對象的地址複製給了形參:

1.此後在方法內部,若是沒有改變形參值(對象的地址),那麼能夠經過該形參操做原實參指向的堆中的對象。這樣雖然原對象的屬性可能發生變化,但原實參的值(指向的地址)並無發生變化。例:

// 設 Student 類對象有 name 和 age 兩個屬性

public static void main(String[] args) {
    Student student = new Student("張三",18);
    System.out.println("原對象的hashCode值:"+student.hashCode());
    referenceTest(student);

    System.out.println("測試後的原對象:"+student);
    System.out.println("測試後原對象的hashCode值:"+student.hashCode());
}

public static void referenceTest(Student stu){
    System.out.println("改變前形參指向對象的hashCode值:"+stu.hashCode());

    stu.setName("李四");
    System.out.println("改變後形參指向的對象:"+stu);
    System.out.println("改變後形參指向對象的hashCode值:"+stu.hashCode());
}

運行結果:(這裏 hashCode 值可表明地址)

原對象的hashCode值:21685669

改變前形參指向對象的hashCode值:21685669
改變後形參指向的對象:Student{name='李四', age=18}
改變後形參指向對象的hashCode值:21685669

測試後的原對象:Student{name='李四', age=18}
測試後原對象的hashCode值:21685669

2.若是該形參指向其它對象,或者指向新 new 的對象,那麼形參值變爲新對象的內存地址。此後經過該形參操做的會是新的對象,原實參的值(指向的地址)不會發生變化。例:

// 設 Student 類對象有 name 和 age 兩個屬性

public static void main(String[] args) {
    Student student = new Student("張三",18);
    System.out.println("原對象的hashCode值:"+student.hashCode());
    referenceTest(student);

    System.out.println("測試後的原對象:"+student);
    System.out.println("測試後原對象的hashCode值:"+student.hashCode());
}

public static void referenceTest(Student stu){
    System.out.println("改變前形參指向對象的hashCode值:"+stu.hashCode());

    stu = new Student("王五",21);
    System.out.println("改變後形參指向的對象:"+stu);
    System.out.println("改變後形參指向對象的hashCode值:"+stu.hashCode());
}

運行結果:(這裏 hashCode 值可表明地址)

原對象的hashCode值:21685669

改變前形參指向對象的hashCode值:21685669
改變後形參指向的對象:Student{name='王五', age=21}
改變後形參指向對象的hashCode值:2133927002  // 有變化

測試後的原對象:Student{name='張三', age=18}
測試後原對象的hashCode值:21685669

即,此後在方法中對形參的操做並不會影響到原來的實參值(原對象的地址)。


參考博文:


若有問題,歡迎交流~ 歡迎您的點贊、收藏和評論!
相關文章
相關標籤/搜索