JAVA中值傳遞和引用傳遞的三種情況

http://blog.csdn.net/zhzhao999/article/details/53449504


在Java裏面參數傳遞都是按值傳遞

這句話的意思是:按值傳遞是傳遞的值的拷貝,按引用傳遞其實傳遞的是引用的地址值,所以統稱按值傳遞。

有個特殊情況容易在面試的時候遇到,String類

在Java裏面除了基本類型,還有按照String方式實現的類是按值傳遞,其它的都是按引用傳遞。關於String類其實還應該有更深入的解析,下次再單獨解釋。


所以關於值傳遞,博客上有個朋友寫的很好,我直接引用

http://blog.csdn.net/zhzhao999/article/details/53449504




前言

我們都知道,java中數據類型分爲基本數據類型和引用數據類型。

  • 基本數據類型 
    • 整型:byte,short,int,long
    • 浮點型:float,double
    • 字符型:char
    • 布爾型:boolean
  • 引用數據類型 
    • 數組
    • 類 
    • 接口

方法的參數分爲實際參數,和形式參數。

  • 形式參數:定義方法時寫的參數。
  • 實際參數:調用方法時寫的具體數值。

一般情況下,在數據做爲參數傳遞的時候,基本數據類型是值傳遞,引用數據類型是引用傳遞(地址傳遞)。

值傳遞

public static void main(String[] args) {
    int num1 = 10;
    int num2 = 20;

    swap(num1, num2);

    System.out.println("num1 = " + num1);
    System.out.println("num2 = " + num2);
}

public static void swap(int a, int b) {
    int temp = a;
    a = b;
    b = temp;

    System.out.println("a = " + a);
    System.out.println("b = " + b);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

運行的結果是:

a = 20
b = 10
num1 = 10
num2 = 20
  • 1
  • 2
  • 3
  • 4

原因:

流程:

  1. 主函數進棧,num1、num2初始化。
  2. 調用swap方法,swap( )進棧,將num1和num2的,複製一份給a和b。
  3. swap方法中對a、b的值進行交換。
  4. swap方法運行完畢,a、b的值已經交換。
  5. swap方法彈棧。
  6. 主函數彈棧。

解析:

在swap方法中,a、b的值進行交換,並不會影響到num1、num2。因爲,a、b中的值,只是從num1、num2的複製過來的。 
也就是說,a、b相當於num1、num2的副本,副本的內容無論怎麼修改,都不會影響到原件本身。

引用傳遞

public static void main(String[] args) {
    int[] arr = {1,2,3,4,5};

    change(arr);

    System.out.println(arr[0]);
}

//將數組的第一個元素變爲0
public static void change(int[] array) {
    int len = array.length;
    array[0] = 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

運行的結果是:

0
  • 1

原因:

流程:

  1. 主函數進棧,int[] arr初始化。
  2. 調用change方法,change( )進棧,將arr的地址值,複製一份給array。
  3. change方法中,根據地址值,找到堆中的數組,並將第一個元素的值改爲0。
  4. change方法運行完畢,數組中第一個元素的值已經改變。
  5. change方法彈棧。
  6. 主函數彈棧。

解析:

調用change()的時候,形參array接收的是arr地址值的副本。並在change方法中,通過地址值,對數組進行操作。change方法彈棧以後,數組中的值已經改變。main方法中,打印出來的arr[0]也就從原來的1變成了0.

無論是主函數,還是change方法,操作的都是同一個地址值對應的數組。 
就像你把自己家的鑰匙給了另一個人,這個人拿着鑰匙在你家一頓瞎折騰,然後走了。等你拿着鑰匙回到家以後,家裏已經變成了被折騰過後,慘不忍睹的樣子。。 
這裏的鑰匙就相當於地址值,家就相當於數組本身。

String類型傳遞

public static void main(String[] args) {
    String str = "AAA";

    change(str);

    System.out.println(str);
}   
public static void change(String s) {
    s = "abc";
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

運行的結果是:

AAA
  • 1

這就神奇了!!! 
String是一個類,類是引用數據類型,做爲參數傳遞的時候,應該是引用傳遞。但是從結果看起來卻是值傳遞。

原因:

String的API中有這麼一句話:“their values cannot be changed after they are created”, 
意思是:String的值在創建之後不能被更改。 
API中還有一段: 
String str = "abc"; 
等效於: 
char data[] = {'a', 'b', 'c'}; 
String str = new String(data); 
也就是說:對String對象str的任何修改 等同於 重新創建一個對象,並將新的地址值賦值給str。

這樣的話,上面的代碼就可以寫成:

public static void main(String[] args) {
    String str1 = "AAA";

    change(str1);

    System.out.println(str1);
}   
public static void change(String s) {
    char data[] = {'a', 'b', 'c'}
    String str = new String(data);
    s = str;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

流程:

  1. 主函數進棧,str1初始化。
  2. 調用change方法,change( )進棧,將str1的地址值,複製一份給s。
  3. change方法中,重現創建了一個String對象”abc”,並將s指向了新的地址值。
  4. change方法運行完畢,s所指向的地址值已經改變。
  5. change方法彈棧。
  6. 主函數彈棧。

解析:

String對象做爲參數傳遞時,走的依然是引用傳遞,只不過String這個類比較特殊。 
String對象一旦創建,內容不可更改。每一次內容的更改都是重現創建出來的新對象。 
當change方法執行完畢時,s所指向的地址值已經改變。而s本來的地址值就是copy過來的副本,所以並不能改變str1的值。

String類型類似情況:

class Person {
    String name;

    public Person(String name) {
        this.name = name;
    }
}
public class Test {
    public static void main(String[] args) {
        Person p = new Person("張三");

        change(p);

        System.out.println(p.name);
    }

    public static void change(Person p) {
        Person person = new Person("李四");
        p = person; 
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

運行的結果是:

張三
  • 1

總結

  • 值傳遞的時候,將實參的,copy一份給形參。
  • 引用傳遞的時候,將實參的地址值,copy一份給形參。

也就是說,不管是值傳遞還是引用傳遞,形參拿到的僅僅是實參的副本,而不是實參本身。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章