為什么說java只有值傳遞?


如果你學的第一門程序語言是java可能對這個傳遞方式沒有那么敏感,如果學了c或c++,然后再學java,那么可能對這個問題會感到困惑。

1.值傳遞與引用傳遞的概念

在將傳遞方式之前先理解一下形參與實參。

形式參數:是在定義函數名和函數體的時候使用的參數,目的是用來接收調用該函數時傳入的參數。

實際參數:在調用有參函數時,主調函數和被調函數之間有數據傳遞關系。在主調函數中調用一個函數時,函數名后面括號中的參數稱為“實際參數”。

可以這么理解:形參是實參的抽象,實參是調用時的參數,形參是定義函數的參數

值傳遞:方法調用時,實際參數把它的值傳遞給對應的形式參數,函數接收的是原始值的一個copy,此時內存中存在兩個相等的基本類型,即實際參數和形式參數,后面方法中的操作都是對形參這個值的修改,不影響實際參數的值。

引用傳遞:是指在調用函數時將實際參數的地址直接傳遞到函數中,那么在函數中對參數所進行的修改,將影響到實際參數。

划重點:值傳遞和引用傳遞的主要區別

值傳遞

引用傳遞

創建副本,在函數體中不能改變原來的值

不創建副本,在在函數體中不能改變原來的值

 創建副本的含義看圖:

創建副本也就是說,把要調用的實參先拷貝一份出來,然后用拷貝的那一份傳進函數體內。不創建副本時,不會發生copy這個步驟。

舉個值傳遞的栗子:

 1 public class Test01 {
 2     public static void main(String[] args) {
 3         int a=1,b=2;
 4         swap(a, b);
 5         System.out.println("a="+a);
 6         System.out.println("b="+b);
 7     }
 8     public static void swap(int a,int b) {
 9         int temp=a;
10         a=b;
11         b=temp;
12     }
13 }

結果:

1 a=1
2 b=2

上面栗子中,在函數中讓實現a,b交換,但調用函數后,輸出的結果仍然是a,b原來的值,說明函數體中的操作並不能影響a,b在函數體外的值。

引用傳遞的栗子就不測試了,有興趣的話可以用c++來測試,參數為定義為別名或指針時,在c++中是引用傳遞。

誤區:傳遞的參數如果是普通類型,那就是值傳遞,如果是對象,那就是引用傳遞。這是錯誤的!!!!!

2.java中的值傳遞

 在java中,無論參數是基本類型,還是引用數據類型,都是值傳遞方式。下面來舉個引用數據類型的參數,基本數據類型傳參的栗子上面已經有了。

 1 public class Test01 {
 2     public static void  swap(Student st1,Student st2) {
 3         Student temp=st1;
 4         st1=st2;
 5         st2=temp;
 6     }
 7         
 8     public static void main(String[] args) {
 9         Student st1=new Student("張三",20);
10         Student st2=new Student("李四",20);
11         swap(st1, st2);
12         System.out.println("st1:"+st1);
13         System.out.println("st2:"+st2);
14 }

結果:

1 st1:Student [name=張三, age=20]
2 st2:Student [name=李四, age=20]

例子中,st1和st2的所指向的對象並沒有發生改變。

這時候,你可能會問,既然java是值傳遞,那么實參會發生拷貝,那拷貝的是什么東西呢?答案是:拷貝的是對象在堆中的地址。來個栗子來驗證一下:

 

 1 public class Test01 {
 2     public static void  print(Student stu1,Student stu2) {
 3         Student temp=stu1;
 4         stu1=stu2;
 5         stu2=temp;
 6         System.out.println("在函數體中交換后打印stu1:  "+stu1);
 7         System.out.println("在函數體中交換后打印stu2:  "+stu2);
 8     }
 9         
10     public static void main(String[] args) {
11         Student stu1=new Student("stu1",20);
12         Student stu2=new Student("stu2",30);
13         print(stu1, stu2);
14     }
15 }

結果:

1 在函數體中交換后打印stu1:  Student [name=stu2, age=30]
2 在函數體中交換后打印stu2:  Student [name=stu1, age=20]

從結果中可以看出,在函數體中stu1stu2所指向的對象確實是發生了改變,這是因為在值傳遞的過程中拷貝了他們在堆中的地址。

來看看他們在內存中是怎么樣的:

這時候你可能會問,既然java的值傳遞是拷貝地址,那我能不能改變地址所指向的內容?答案是:當然可以

1     public static void  changeInf(Student stu) {
2         stu.setName("我改名字了");
3     }
4         
5     public static void main(String[] args) {
6         Student stu=new Student("張三",18);
7         changeInf(stu);
8         System.out.println(stu);
9     }

結果:

1 Student [name=我改名字了, age=18]

對象內容改變了

結論:java中只有值傳遞,這可能是因為java沒有指針和別名引用的原因吧。


免責聲明!

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



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