Java值傳遞

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

概覽

傳遞

這個(gè)問題一般是相對函數(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è)方法可以修改傳遞引用所對應(yīng)的變量值往果,而不能修改傳遞值調(diào)用所對應(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ù)類型丑瞧,也就是對象引用柑土,那么對于這種數(shù)據(jù)類型又是怎么樣的情況呢?我們還是一樣先來看一個(gè)例子:

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

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ù)類型如果是引用類型的話,引用類型對應(yīng)的值將會被修改

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

image

過程分析:

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

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

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

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

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

但是對象的地址不變蜓斧。

3. swap

可通過上面的實(shí)例我們可能就會覺得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è)方法可以修改傳遞引用所對應(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ā)生變化邮绿,也就是方法并沒有改變存儲在變量user和stu中的對象引用。swap方法的參數(shù)x和y被初始化為兩個(gè)對象引用的拷貝攀例,這個(gè)方法交換的是這兩個(gè)拷貝的值而已船逮,最終,所做的事都是白費(fèi)力氣罷了粤铭。在方法結(jié)束后x挖胃,y將被丟棄,而原來的變量user和stu仍然引用這個(gè)方法調(diào)用之前所引用的對象。

swap

這個(gè)過程也充分說明了java程序設(shè)計(jì)語言對對象采用的不是引用調(diào)用酱鸭,實(shí)際上是對象引用進(jìn)行的是值傳遞吗垮,當(dāng)然在這里我們可以簡單理解為這就是按值調(diào)用和引用調(diào)用的區(qū)別,而且必須明白即使java函數(shù)在傳遞引用數(shù)據(jù)類型時(shí)凛辣,也只是拷貝了引用的值罷了抱既,之所以能修改引用數(shù)據(jù)是因?yàn)樗鼈兺瑫r(shí)指向了一個(gè)對象,但這仍然是按值調(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. 對象是按引用傳遞的
  • 一個(gè)方法不能修改一個(gè)基本數(shù)據(jù)類型的參數(shù)(數(shù)值型和布爾型)
  • 一個(gè)方法可以修改一個(gè)引用所指向的對象狀態(tài)捷泞,但這仍然是按值調(diào)用而非引用調(diào)用
    (只是修改了屬性,沒有改動對象地址)
  1. Java 有且僅有的一種參數(shù)傳遞機(jī)制寿谴,即按值傳遞

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市讶泰,隨后出現(xiàn)的幾起案子咏瑟,更是在濱河造成了極大的恐慌,老刑警劉巖痪署,帶你破解...
    沈念sama閱讀 210,978評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件码泞,死亡現(xiàn)場離奇詭異,居然都是意外死亡狼犯,警方通過查閱死者的電腦和手機(jī)余寥,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評論 2 384
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來悯森,“玉大人宋舷,你說我怎么就攤上這事∑耙觯” “怎么了祝蝠?”我有些...
    開封第一講書人閱讀 156,623評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長幻碱。 經(jīng)常有香客問我续膳,道長,這世上最難降的妖魔是什么收班? 我笑而不...
    開封第一講書人閱讀 56,324評論 1 282
  • 正文 為了忘掉前任,我火速辦了婚禮谒兄,結(jié)果婚禮上摔桦,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好邻耕,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,390評論 5 384
  • 文/花漫 我一把揭開白布鸥咖。 她就那樣靜靜地躺著,像睡著了一般兄世。 火紅的嫁衣襯著肌膚如雪啼辣。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,741評論 1 289
  • 那天御滩,我揣著相機(jī)與錄音鸥拧,去河邊找鬼。 笑死削解,一個(gè)胖子當(dāng)著我的面吹牛富弦,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播氛驮,決...
    沈念sama閱讀 38,892評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼腕柜,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了矫废?” 一聲冷哼從身側(cè)響起盏缤,我...
    開封第一講書人閱讀 37,655評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蓖扑,沒想到半個(gè)月后唉铜,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,104評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡赵誓,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年打毛,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片俩功。...
    茶點(diǎn)故事閱讀 38,569評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡幻枉,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出诡蜓,到底是詐尸還是另有隱情熬甫,我是刑警寧澤,帶...
    沈念sama閱讀 34,254評論 4 328
  • 正文 年R本政府宣布蔓罚,位于F島的核電站椿肩,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏豺谈。R本人自食惡果不足惜郑象,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,834評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望茬末。 院中可真熱鬧厂榛,春花似錦盖矫、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至柜砾,卻和暖如春湃望,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背痰驱。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評論 1 264
  • 我被黑心中介騙來泰國打工证芭, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人萄唇。 一個(gè)月前我還...
    沈念sama閱讀 46,260評論 2 360
  • 正文 我出身青樓檩帐,卻偏偏與公主長得像,于是被迫代替她去往敵國和親另萤。 傳聞我的和親對象是個(gè)殘疾皇子湃密,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,446評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法四敞,內(nèi)部類的語法泛源,繼承相關(guān)的語法,異常的語法忿危,線程的語...
    子非魚_t_閱讀 31,597評論 18 399
  • 周末休閑游龍山达箍, 晴空萬里望無邊。 密林叢中幽靜路铺厨, 空氣清新沁心田缎玫。 翹首登高攬勝樓, 遙望群山似海藍(lán)解滓。 山澗小...
    笑傲江湖之秋雨閱讀 220評論 0 2
  • 萬水千山總是情。 重慶腮鞍,一座很有特色值骇,很有味道的溫情城市。 霧都山城移国,不是徒有虛名吱瘩,山霧說來就來,從不提前打招呼…...
    龍井春天閱讀 319評論 0 0
  • AmeeLove閱讀 297評論 0 0
  • 周五的時(shí)候迹缀,趁早讀書會臨時(shí)通知晚上有個(gè)單人互動話劇使碾,想想上次看話劇也是兩年前的事情了皱卓,所以就報(bào)名參加了。 這次的話...
    洮小夭_Amy閱讀 290評論 0 0