1. 程式人生 > >java基礎–(11)–關於Java中的值傳遞與“引用傳遞”

java基礎–(11)–關於Java中的值傳遞與“引用傳遞”

結論:Java中都是值傳遞,沒有“引用傳遞”

(1)基本資料型別傳值,對形參的修改不會影響實參;
(2)引用型別傳引用的值,形參和實參指向同一個記憶體地址(同一個物件),所以對引數的修改會影響到實際的物件;
(3)String, Integer, Double等immutable的型別特殊處理,可以理解為傳值,最後的操作不會修改實參物件。

下面來進行詳解:

首先回顧一下在程式設計語言中有關將引數傳遞給方法(或函式)的一些專業術語。按值呼叫(call by value)表示方法接收的是呼叫者提供的值,而按引用呼叫(call by reference)表示方法接收的是呼叫者提供的變數地址。一個方法可以修改傳遞引用所對應的變數值,而不能修改傳遞值呼叫所對應的變數值。

 它用來描述各種程式設計語言(不只是Java)中方法引數傳遞方式。

Java程式設計語言總是採用按值呼叫。也就是說,方法得到的是所有引數值的一個拷貝,也就是說,方法不能修改傳遞給它的任何引數變數的內容。

Example1

    @Test
    public void testInt() {
        int num1 = 10;
        int num2 = 20;

        swapInt(num1, num2);

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

    private void swapInt(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

解析:

example 1

在swap方法中,a、b的值進行交換,並不會影響到 num1、num2。因為,a、b中的值,只是從 num1、num2 的複製過來的。也就是說,a、b相當於num1、num2 的副本,副本的內容無論怎麼修改,都不會影響到原件本身。另外即使是String, Integer, Double等immutable,也會是上面的情況,請看Example2

Example2

    @Test
    public void testString() {
        String str1 = "hello";
        String str2 = "world";

        swapString(str1, str2);

        System.out.println("str1 = " + str1);
        System.out.println("str2 = " + str2);
    }

    private void swapString(String a, String b) {
        String temp = a;
        a = b;
        b = temp;

        System.out.println("a = " + a);
        System.out.println("b = " + b);
    }

結果:
a = world
b = hello
str1 = hello
str2 = world

通過上面的例子,我們已經知道了一個方法不能修改一個基本資料型別的引數,而物件引用作為引數不一樣,請看 Example3

Example3

    @Test
    public void testArr() {
        int[] arr = { 1, 2, 3, 4, 5 };
        System.out.println("改變前arr[0] = " + arr[0]);
        changeArr(arr);
        System.out.println("改變後arr[0] = " + arr[0]);
    }

    private void changeArr(int[] array) {
        // 將陣列的第一個元素變為0
        array[0] = 666;
    }

結果:
改變前arr[0] = 1
改變後arr[0] = 666

解析:

example 2

array 被初始化 arr 的拷貝也就是一個物件的引用,也就是說 array 和 arr 指向的時同一個陣列物件。 因此,外部對引用物件的改變會反映到所對應的物件上。

通過 example3 我們已經看到,實現一個改變物件引數狀態的方法並不是一件難事。理由很簡單,方法得到的是物件引用的拷貝,物件引用及其他的拷貝同時引用同一個物件。

很多程式設計語言(特別是,C++和Pascal)提供了兩種引數傳遞的方式:值呼叫和引用呼叫。有些程式設計師認為Java程式設計語言對物件採用的是引用呼叫,實際上,這種理解是不對的。由於這種誤解具有一定的普遍性,所以下面給出一個反例來詳細地闡述一下這個問題。即使傳遞的是一個物件的引用也不會改變原有物件的值

Example4

    @Test
    public void testStudent() {
        Student s1 = new Student("小張");
        Student s2 = new Student("小李");

        swapStudent(s1, s2);
        System.out.println("s1.getName() = " + s1.getName());
        System.out.println("s2.getName() = " + s2.getName());
    }

    private void swapStudent(Student x, Student y) {
        Student temp = x;
        x = y;
        y = temp;
        System.out.println("x.getName() = " + x.getName());
        System.out.println("y.getName() = " + y.getName());
    }

結果:
x.getName() = 小李
y.getName() = 小張
s1.getName() = 小張
s2.getName() = 小李

解析:

交換之前:

交換之後:

通過上面兩張圖可以很清晰的看出: 方法並沒有改變儲存在變數 s1 和 s2 中的物件引用。swap方法的引數x和y被初始化為兩個物件引用的拷貝,這個方法交換的是這兩個拷貝。但是我們可以改變引用的物件的值,擴充套件如下

Example5

    @Test
    public void testStudent2() {
        Student s1 = new Student("張三");
        Student s2 = new Student("李四");

        swapStudent2(s1, s2);
        System.out.println("s1.getName() = " + s1.getName());
        System.out.println("s2.getName() = " + s2.getName());
    }

    private void swapStudent2(Student x, Student y) {
        x.setName("張三三");
        y.setName("李四四");
        System.out.println("x.getName() = " + x.getName());
        System.out.println("y.getName() = " + y.getName());
    }

結果:
x.getName() = 張三三
y.getName() = 李四四
s1.getName() = 張三三
s2.getName() = 李四四

上面的Example5我們發現,通過對x,y的改變可以改變原有的物件的值,主要是看我們是對形參的修改還是對形參指向的物件的修改,其中的區別能感覺到麼 ,如果沒有感覺到。

那就再看一遍Example4,Example5。

再次總結

Java程式設計語言對物件採用的不是引用呼叫,實際上,物件引用是按
值傳遞的。

下面再總結一下Java中方法引數的使用情況:

  • 一個方法不能修改一個基本資料型別的引數(即數值型或布林型》
  • 一個方法可以改變一個物件引數的狀態。
  • 一個方法不能讓物件引數引用一個新的物件。

 

 

 

看這裡,看這裡

文章總目錄:部落格導航

 碼字不易,尊重原創,轉載請註明:https://blog.csdn.net/u_ascend/article/details/82876848

 參考博文:https://github.com/Snailclimb/JavaGuide/issues/12

如果涉及到侵權,請聯絡我:[email protected],1-2個工作日處理。

 

作者自己維護的公眾平臺,感興趣的來,需要什麼可以私聊我,網盤中有大量學習資源,後續慢慢新增。

微信掃一掃

 

 

歡迎互噴