Java值傳遞

面試問到Java的傳遞。答出來了Java是call by value。但是回答不好,現(xiàn)在詳細(xì)分析。

概覽

傳遞

這個(gè)問題一般是相對(duì)函數(shù)而言的,也就是java中的方法參數(shù),兩個(gè)專業(yè)術(shù)語:

  • 按值調(diào)用(call by value)
  • 按引用調(diào)用(call by reference)

區(qū)別

所謂的按值調(diào)用表示方法接收的是調(diào)用著提供的值,而按引用調(diào)用則表示方法接收的是調(diào)用者提供的變量地址(如果是C語言的話來說就是指針啦,當(dāng)然java并沒有指針的概念)。

一個(gè)方法可以修改傳遞引用所對(duì)應(yīng)的變量值,而不能修改傳遞值調(diào)用所對(duì)應(yīng)的變量值

Java程序設(shè)計(jì)語言確實(shí)是采用了按值調(diào)用,即call by value。也就是說方法得到的是所有參數(shù)值的一個(gè)拷貝,方法并不能修改傳遞給它的任何參數(shù)變量的內(nèi)容。

例子分析

1. 基本數(shù)據(jù)類型

例子:

public class TestPass {
    private static int x = 10;

    public static void updateValue(int value) {
        value = 3 * value;
    }

    public static void main(String[] args) {
        System.out.println("調(diào)用前x的值:" + x);
        updateValue(x);
        System.out.println("調(diào)用后x的值:" + x);
    }
}

運(yùn)行程序,結(jié)果如下:

調(diào)用前x的值:10
調(diào)用后x的值:10

可以看到x的值并沒有變化,接下來我們一起來看一下具體的執(zhí)行過程:

基本數(shù)據(jù)類型

分析:

1)value被初始化為x值的一個(gè)拷貝(也就是10)

2)value被乘以3后等于30,但注意此時(shí)x的值仍為10!

3)這個(gè)方法結(jié)束后,參數(shù)變量value不再使用,被回收。

結(jié)論:當(dāng)傳遞方法參數(shù)類型為基本數(shù)據(jù)類型(數(shù)字以及布爾值)時(shí),一個(gè)方法是不可能修改一個(gè)基本數(shù)據(jù)類型的參數(shù)。

2. 引用數(shù)據(jù)類型

當(dāng)然java中除了基本數(shù)據(jù)類型還有引用數(shù)據(jù)類型,也就是對(duì)象引用,那么對(duì)于這種數(shù)據(jù)類型又是怎么樣的情況呢?我們還是一樣先來看一個(gè)例子:

聲明一個(gè)User對(duì)象類型:

public class User {
    private String name;
    private int age;

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}

調(diào)用執(zhí)行類如下:(toString())

public class TestUser {
    private static User user = null;

    public static void updateUser(User student) {
        student.setName("Lishen");
        student.setAge(18);
    }

    public static void main(String[] args) {
        user = new User("zhangsan", 26);
        System.out.println("調(diào)用前user的值:" + user.toString());
        updateUser(user);
        System.out.println("調(diào)用后user的值:" + user.toString());
    }

}

運(yùn)行結(jié)果如下:

調(diào)用前user的值:test.User@532760d8
調(diào)用后user的值:test.User@532760d8

調(diào)用執(zhí)行類如下:(getName())

public class TestUser {
    private static User user = null;

    public static void updateUser(User student) {
        student.setName("Lishen");
        student.setAge(18);
    }

    public static void main(String[] args) {
        user = new User("zhangsan", 26);
        //System.out.println("調(diào)用前user的值:" + user.toString());
        System.out.println("調(diào)用前user的值:" + user.getName());
        updateUser(user);
        //System.out.println("調(diào)用后user的值:" + user.toString());
        System.out.println("調(diào)用前user的值:" + user.getName());
    }
}

運(yùn)行結(jié)果如下:

調(diào)用前user的值:zhangsan
調(diào)用前user的值:Lishen

很顯然,User的值被改變了,也就是說方法參數(shù)類型如果是引用類型的話,引用類型對(duì)應(yīng)的值將會(huì)被修改

下面我們來分析一下這個(gè)過程:

image

過程分析:

1)student變量被初始化為user值的拷貝,這里是一個(gè)對(duì)象的引用。

2)調(diào)用student變量的set方法作用在這個(gè)引用對(duì)象上,user和student同時(shí)引用的User對(duì)象內(nèi)部值被修改。

3)方法結(jié)束后,student變量不再使用,被釋放,而user還是沒有變,依然指向User對(duì)象。

結(jié)論:當(dāng)傳遞方法參數(shù)類型為引用數(shù)據(jù)類型時(shí),一個(gè)方法將修改一個(gè)引用數(shù)據(jù)類型的參數(shù)所指向?qū)ο蟮闹怠?/p>

雖然到這里兩個(gè)數(shù)據(jù)類型的傳遞都分析完了,也明白的基本數(shù)據(jù)類型的傳遞和引用數(shù)據(jù)類型的傳遞區(qū)別,前者將不會(huì)修改原數(shù)據(jù)的值,而后者將會(huì)修改引用所指向?qū)ο蟮闹怠?/p>

但是對(duì)象的地址不變。

3. swap

可通過上面的實(shí)例我們可能就會(huì)覺得java同時(shí)擁有按值調(diào)用和按引用調(diào)用啊,可惜的是這樣的理解是有誤導(dǎo)性的,雖然上面引用傳遞表面上體現(xiàn)了按引用調(diào)用現(xiàn)象,但是Java中確實(shí)只有按值調(diào)用而沒有按引用調(diào)用。到這里估計(jì)不少人都蒙逼了,下面我們通過一個(gè)反例來說明(回憶一下開頭我們所說明的按值調(diào)用與按引用調(diào)用的根本區(qū)別)。

public class TestSwap {
    private static User user = null;
    private static User stu = null;

    public static void swap(User x, User y) {
        User temp = x;
        x = y;
        y = temp;
    }

    public static void main(String[] args) {
        user = new User("user", 26);
        stu = new User("stu", 18);
        System.out.println("調(diào)用前user的值:" + user.toString());
        System.out.println("調(diào)用前stu的值:" + stu.toString());
        swap(user, stu);
        System.out.println("調(diào)用后user的值:" + user.toString());
        System.out.println("調(diào)用后stu的值:" + stu.toString());

    }
}

我們通過一個(gè)swap函數(shù)來交換兩個(gè)變量user和stu的值,在前面我們說過,如果是按引用調(diào)用那么一個(gè)方法可以修改傳遞引用所對(duì)應(yīng)的變量值,也就是說如果java是按引用調(diào)用的話,那么swap方法將能夠?qū)崿F(xiàn)數(shù)據(jù)的交換,而實(shí)際運(yùn)行結(jié)果是:

調(diào)用前user的值:test.User@532760d8
調(diào)用前stu的值:test.User@57fa26b7
調(diào)用后user的值:test.User@532760d8
調(diào)用后stu的值:test.User@57fa26b7

我們發(fā)現(xiàn)user和stu的值并沒有發(fā)生變化,也就是方法并沒有改變存儲(chǔ)在變量user和stu中的對(duì)象引用。swap方法的參數(shù)x和y被初始化為兩個(gè)對(duì)象引用的拷貝,這個(gè)方法交換的是這兩個(gè)拷貝的值而已,最終,所做的事都是白費(fèi)力氣罷了。在方法結(jié)束后x,y將被丟棄,而原來的變量user和stu仍然引用這個(gè)方法調(diào)用之前所引用的對(duì)象。

swap

這個(gè)過程也充分說明了java程序設(shè)計(jì)語言對(duì)對(duì)象采用的不是引用調(diào)用,實(shí)際上是對(duì)象引用進(jìn)行的是值傳遞,當(dāng)然在這里我們可以簡(jiǎn)單理解為這就是按值調(diào)用和引用調(diào)用的區(qū)別,而且必須明白即使java函數(shù)在傳遞引用數(shù)據(jù)類型時(shí),也只是拷貝了引用的值罷了,之所以能修改引用數(shù)據(jù)是因?yàn)樗鼈兺瑫r(shí)指向了一個(gè)對(duì)象,但這仍然是按值調(diào)用而不是引用調(diào)用。

總結(jié)

  1. 按值傳遞意味著當(dāng)將一個(gè)參數(shù)傳遞給一個(gè)函數(shù)時(shí),函數(shù)接收的是原始值的一個(gè)副本
  2. 按引用傳遞意味著當(dāng)將一個(gè)參數(shù)傳遞給一個(gè)函數(shù)時(shí),函數(shù)接收的是原始值的內(nèi)存地址,而不是值的副本
  3. 對(duì)象是按引用傳遞的
  • 一個(gè)方法不能修改一個(gè)基本數(shù)據(jù)類型的參數(shù)(數(shù)值型和布爾型)
  • 一個(gè)方法可以修改一個(gè)引用所指向的對(duì)象狀態(tài),但這仍然是按值調(diào)用而非引用調(diào)用
    (只是修改了屬性,沒有改動(dòng)對(duì)象地址)
  1. Java 有且僅有的一種參數(shù)傳遞機(jī)制,即按值傳遞

參考文章
java中的參數(shù)傳遞——值傳遞、引用傳遞
java基本數(shù)據(jù)類型傳遞與引用傳遞區(qū)別詳解

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 34,628評(píng)論 18 399
  • 周末休閑游龍山, 晴空萬里望無邊。 密林叢中幽靜路, 空氣清新沁心田。 翹首登高攬勝樓, 遙望群山似海藍(lán)。 山澗小...
    笑傲江湖之秋雨閱讀 255評(píng)論 0 2
  • 萬水千山總是情。 重慶,一座很有特色,很有味道的溫情城市。 霧都山城,不是徒有虛名,山霧說來就來,從不提前打招呼…...
    龍井春天閱讀 369評(píng)論 0 0
  • AmeeLove閱讀 318評(píng)論 0 0
  • 周五的時(shí)候,趁早讀書會(huì)臨時(shí)通知晚上有個(gè)單人互動(dòng)話劇,想想上次看話劇也是兩年前的事情了,所以就報(bào)名參加了。 這次的話...
    洮小夭_Amy閱讀 344評(píng)論 0 0

友情鏈接更多精彩內(nèi)容