Java的參數傳遞是值傳遞還是引用傳遞?


一、前言

  首先先說結論,Java中方法參數傳遞方式是按值傳遞。如果參數是基本類型,傳遞的是基本類型的字面量值的拷貝。如果參數是引用類型,傳遞的是該參量所引用的對象在堆中地址值的拷貝。

  接下來深入了解一下為什么是值傳遞,要想知道Java到底是傳值還是傳引用,首先要知道基本類型和引用類型的區別。

二、深入了解參數傳遞

  1.基本類型 和 引用類型的不同之處

基本類型包括8種數據類型:int、short、long、byte、char、float、double、boolean,在方法中定義的非全局基本數據類型變量的具體內容是存儲在棧中的;除了基本類型以外的都是引用類型:類、接口類型、數組類型、字符串類型都是引用類型,引用類型變量其具體內容都是存放在堆中的,而棧中存放的是其具體內容所在內存的地址(字符串類型比較特殊,涉及到字符串常量池,這里不做深入研究)。

示例:

int num = 10;      
String str = new String("hello");

 

注:該圖的堆區是經過簡化的,實際的情況會復雜點,這里只作示意

如圖所示,num是基本類型,值就直接保存在變量中。而str是引用類型,變量中保存的只是實際對象的地址。一般稱這種變量為"引用",引用指向實際對象,實際對象在堆中並保存着實際內容。

  2.賦值運算符(=)的作用

num = 20;
str = "world";
注:該圖的堆區是經過簡化的,實際的情況會復雜點,這里只作示意
 
對於基本類型 num ,賦值運算符會直接改變變量的值,原來的值被覆蓋掉。
對於引用類型 str,賦值運算符會改變引用中所保存的地址,原來的地址被覆蓋掉。 但是原來的對象不會被改變。如上圖所示,"world" 字符串對象沒有被改變。(沒有被任何引用所指向的對象是垃圾,會被垃圾回收器回收)。
   3.值傳遞和引用傳遞的區別
值傳遞是指在調用函數時將實際參數復制一份傳遞到函數中,引用傳遞是指在調用函數時將實際參數的地址直接傳遞到函數中,所以值傳遞和引用傳遞的根本區別是是否會復制一份副本。
   4.實例
   例子一(基本數據類型):   
public static void main(String[] args) {
   Test test = new Test();

    int i = 10;
    test.print(10);
    System.out.println("main方法輸出i:" + i);
}

public void print(int j) {
    j = 20;
    System.out.println("print方法輸出j:" + j);
}

  結果:

print方法輸出j:20
main方法輸出i:10

這個例子應該還是很好理解的,test.print(10)將10作為參數傳給print方法, 將10拷貝一份給 j,修改 j 不會影響 i 。

  例子二(引用數據類型):

public static void main(String[] args) {
    Test test = new Test();
    User user = new User();
    user.setName("Tom");
    user.setAge("18");
    test.print(user);
    System.out.println("main方法輸出用戶:" + user);
}

public void print(User user1) {
    user1.setName("Mike");
    System.out.println("print方法輸出用戶:" + user1);
}

  結果:

print方法輸出用戶:User{name="Mike",age="18"}
main方法輸出用戶:User{name="Mike",age="18"}

  解釋: test.print(user)將user對象的引用(即user對象的內存地址)拷貝一份給形參的user1,也就是說main方法中的user引用和print方法的user1引用都指向堆中的同一個user對象,所以user1修改user對象的數據,user的也會相應的改變。

  user1.setName("Mike")執行前

  user1.setName("Mike")執行后

注意:引用數據類型中的字符串類型比較特殊,String被設計成為了不可變類型,為String賦值時不會覆蓋以前的對象而是引用一個新的字符串對象(如果新的字符串在常量池中直接返回其引用,否則創建一個字符串對象,詳情可以去我的另一篇關於常量池的博客),在這里我們不考慮新字符串在常量池的情況。
  下面來看各String類型的例子:
public static void main(String[] args) {
    Test test = new Test();
    String name = new String("Tom");
    test.print(name);
    System.out.println("main方法輸出name:" + name);
}

public void print(String name1) {
    name1 = "Mike";
    System.out.println("print方法輸出name1:" + name1);
}

  結果:

print方法輸出name1:Mike
main方法輸出name:Tom

  解釋:由於String被設計成為了不可變類型,為name賦值時不會覆蓋以前的對象而是創建一個新的字符串對象並返回引用。

  name1 = "Mike"執行前

  name1 = "Mike"執行后

三、總結

Java中方法參數傳遞方式是按值傳遞。如果參數是基本類型,傳遞的是基本類型的數據拷貝。如果參數是引用類型,因為棧中存的是對象的地址值,所以傳遞的是該參量所引用的對象在堆中地址值的拷貝,除了特殊的String類型,形參對象可以影響實參對象的值。

 


免責聲明!

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



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