Java方法中傳值和引用傳遞的問題(轉)


說明:標題其實說法是錯誤的。Java中只有值傳遞,沒有引用傳遞。

... ...  
//定義了一個改變參數值的函數  
public static void changeValue(int x) {  
    x = x *2;  
}  
... ...  
//調用該函數  
int num = 5;  
System.out.println(num);  
changeValue(num);  
System.out.println(num);  
... ...  

調用函數changeValue()前后num的值都沒有改變。

值傳遞的過程:

num作為參數傳遞給changeValue()方法時,是將內存空間中num所指向的那個存儲單元中存放的值,即"5",傳送給了changeValue()方法中的x變量,而這個x變量也在內存空間中分配了一個存儲單元,這個時候,就把num的值5傳送給了這個存儲單元中。此后,在changeValue()方法中對x的一切操作都是針對x所指向的這個存儲單元,與num所指向的那個存儲單元沒有關系!

自然,在函數調用之后,num所指向的存儲單元的值還是沒有發生變化,這就是所謂的“值傳遞”!值傳遞的精髓是:傳遞的是存儲單元中的內容,而非地址或者引用!

... ...  
class person {  
public static String name = "Jack";  
    ... ...  
}  
... ...  
//定義一個改變對象屬性的方法  
public static void changeName(Person p) {  
    p.name = "Rose";  
}  
... ...  
public static void main(String[] args) {  
    //定義一個Person對象,person是這個對象的引用  
    Person person = new Person();  
    //先顯示這個對象的name屬性  
    System.out.println(person.name);  
    //調用changeName(Person p)方法  
    changeName(person);  
    //再顯示這個對象的name屬性,看是否發生了變化  
    System.out.println(person.name);  
}  

第一次顯示:“Jack”

第二次顯示:“Rose”

方法用了一個對象參數,該對象內部的內容就可以改變,之前一直認為應該是該對象復制了一個引用副本給調用函數的參數,使得該方法可以對這個對象進行操作,其實是錯了!

Java編程語言只有值傳遞參數。當一個對象實例作為一個參數被傳遞到方法中時,參數的值就是該對象的引用一個副本。指向同一個對象,對象的內容可以在被調用的方法中改變,但對象的引用(不是引用的副本)是永遠不會改變的。  

為什么這里是“值傳遞”,而不是“引用傳遞”?

主函數中new了一個對象Person,實際分配了兩個對象:新創建的Person類的實體對象,和指向該對象的引用變量person。

注意:在Java中,新創建的實體對象在堆內存中開辟空間,而引用變量在棧內存中開辟空間

正如如上圖所示,左側是堆空間,用來分配內存給新創建的實體對象,紅色框是新建的Person類的實體對象,000012是該實體對象的起始地址;而右側是棧空間,用來給引用變量和一些臨時變量分配內存,新實體對象的引用person就在其中,可以看到它的存儲單元的內容是000012,記錄的正是新建Person類實體對象的起始地址,也就是說它指向該實體對象。

調用了changeName()方法,person作為對象參數傳入該方法,person引用變量將自己的存儲單元的內容傳給了changeName()方法的p變量!也就是將實體對象的地址傳給了p變量,從此,在changeName()方法中對p的一切操作都是針對p所指向的這個存儲單元,與person引用變量所指向的那個存儲單元再沒有關系!

p所指向的那個存儲單元中的內容是實體對象的地址,使得p也指向了該實體對象,所以才能改變對象內部的屬性!

示例參考:

package com.jsoft.testjavabasics.test1;

/**
 * This is Description
 *
 * @author jim
 * @date 2017/11/25
 */
public class TestClass {

    private void add(int i, int j) {
        i += 1;
        j += 1;
    }

    private void add(Integer a, Integer b) {
        a += 1;
        b += 1;
    }

    private int add(int i) {
        return ++i;
    }

    private Integer add(Integer a) {
        return ++a;
    }

    private void add(Integer[] integers) {
        integers[0] = 2;
        integers[1] = 2;
    }

    public void run() {

        int i = 1;
        int j = 1;

        add(i, j);

        System.out.println("add method:i:" + i + " j:" + j);
        // out:add method:i:1 j:1

        Integer a = 1;
        Integer b = 1;

        add(a, b);

        System.out.println("add method:a:" + a + " b:" + b);
        // out:add method:a:1 b:1

        i = add(i);

        System.out.println("add method:i:" + i);
        // out:add method:i:2

        a = add(a);

        System.out.println("add method:a:" + a);
        // out:add method:a:2


        Integer[] integers = new Integer[2];
        integers[0] = 1;
        integers[1] = 1;
        add(integers);

        System.out.println("add method:integers[0]:" + integers[0] + " integers[1]:" + integers[1]);
        // out:add method:integers[0]:2 integers[1]:2

    }
}

示例工程:https://github.com/easonjim/5_java_example/tree/master/javabasicstest/test30/test1

 

參考:

http://lyy3323.iteye.com/blog/609068

http://ask.csdn.net/questions/206076

http://bbs.csdn.net/topics/391065642?page=1

http://guhanjie.iteye.com/blog/1683637(以上內容轉自此篇文章)

http://bbs.csdn.net/topics/390900983?page=1


免責聲明!

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



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