值傳遞與引用傳遞的區別

值傳遞與引用傳遞的理解一直不深,查看了很多的博客總結了自己的理解。如有錯誤,可以指出改正。

在瞭解引用傳遞之前,我們首先了解一下 什麼是引用,其作用到底是什麼?

1 引用是什麼?

在這裏插入圖片描述
可以說str這個變量是實例對象地址的一個別名

2 基本類型和引用類型

Java中數據類型分爲基本類型的引用類型兩大類

基本類型: byte、short、int、long、float、double、boolean、char
引用類型: 類、接口、數組

基本類型的變量在聲明時就會分配數據空間
而引用類型在聲明時只是給變量分配了引用空間,並不分配數據空間

3 值傳遞和引用傳遞

  1. 方法調用時,實際參數把它的值傳遞給方法的形參,形參接收的只是原始值的一個副本,後續方法裏對形參的修改不會影響原來的實參的值
  2. 在方法的執行過程中,形參和實參的內容相同,指向同一塊內存地址,也就是說操作的其實都是源數據,所以方法的執行將會影響到實際對象。

注意: 在JAVA中所有的傳遞其實都是值傳遞,只不過區分於理解,加了引用傳遞而已。(其實在引用傳遞的時候,是把實參的地址傳遞給了形參而已)

4 實際理解

4.1 值傳遞

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);
}

運行結果:

a = 20
b = 10
num1 = 10
num2 = 20

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

4.2 引用傳遞

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) {
    array[0] = 0;
}

輸出結果:

0

解析:

假設arr指向的內存地址是0x11
實參arr黑色,形參array紅色。
調用change()的時候,形參array接收的是arr地址值的副本,此時的array也指向了0x11。
在change方法中對0x11地址裏面的值進行了修改,導致0x11地址中存儲的值變爲了0。
所以輸出爲arr[0]輸出結果爲0
在這裏插入圖片描述

在看一段代碼,我們都知道String和基本類型的包裝類都是不可變類。

  1. 什麼是不可變類?
    就是該類被final修飾,創建了這個類的實例之後,就不容許改變他的值了。

看一下這些的源碼是否被final修飾。
在這裏插入圖片描述
在這裏插入圖片描述

在看如下的代碼解析過程。

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

    change(str);

    System.out.println(str);
}   
public static void change(String s) {
    s = "wolrd";
}

輸出結果:

Hello

發現是不是和我們理解的,有點有出入?
在調用change方法的時候,str把他的地址副本拷貝了一份給了s。
此時的str和s都指向了一個字符串常量"hello"
那麼爲什麼s = "wolrd"的操作 並沒有影響到str呢?
在這裏插入圖片描述

String的API中有這麼一句話:“their values cannot be changed after they are created”,
意思是:String的值在創建之後不能被更改,因爲String是不可變類 被final修飾的。
API中還有一段:
String str = “abc”;
等效於:
char data[] = {‘a’, ‘b’, ‘c’};
String str = new String(data);

也就是說:對String對象str的任何修改 等同於 重新創建一個對象,並將新的地址值賦值給str。

實際上,可以轉換成一種理解。

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

    change(str1);

    System.out.println(str1);
}   
public static void change(String s) {
    char data[] = {'w', 'o', 'r','l','d'};
    String str = new String(data);
    s = str;
}

然後引用指向的地址是。
在這裏插入圖片描述

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 p1) {
        Person person = new Person("李四");
        p1 = person; 
    }
}

輸出結果:

張三

那麼爲什麼輸出結果是張三呢?看圖。
在調用change方法的時候 p和p1指向通一個內存地址。
在這裏插入圖片描述
在change方法裏面執行如下內容之後,p1的內存地址改變了。
Person person = new Person(“李四”);

在這裏插入圖片描述

最後的總結內容是:
值傳遞的時候,將實參的值,copy一份給形參。
引用傳遞的時候,將實參的地址值,copy一份給形參。
也就是說,不管是值傳遞還是引用傳遞,形參拿到的僅僅是實參的副本,而不是實參本身。

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