java漫談-Java只有值傳遞

本文首發(fā)WindCoder:java漫談-Java只有值傳遞

《Head First Java》中關(guān)于 Java 參數(shù)傳遞的說明:

Java 中所傳遞的所有東西都是值杂靶,但此值是變量所攜帶的值甜无。引用對(duì)象的變量所攜帶的是遠(yuǎn)程控制而不是對(duì)象本身,若你對(duì)方法傳入?yún)?shù)唉侄,實(shí)際上傳入的是遠(yuǎn)程控制的拷貝个曙。

《Java編程思想 第四版》中第二章第一節(jié)“用引用操作對(duì)象”中寫到:

盡管一切都看作對(duì)象憔足,但操作的標(biāo)識(shí)符實(shí)際上是一個(gè)對(duì)象的引用(reference)酪夷。

文中用遙控器(引用)操作電視(對(duì)象)為例形象的說明了該引用名詞的含義贰镣,同時(shí)在對(duì)定義的“引用”該名詞的注釋中提到:

有人認(rèn)為:“很明顯呜象,它是一個(gè)指針”。”但是這種說法是基于底層實(shí)現(xiàn)的某種假設(shè)恭陡。并且,Java中的引用上煤,在語(yǔ)法上更接近C++的引用而不是指針休玩。

還是有很多人不同意用“引用”這個(gè)術(shù)語(yǔ)。我曾讀到的一本書中這樣說:“Java所支持的‘按址傳遞’是完全錯(cuò)誤的”劫狠,因?yàn)镴ava對(duì)象標(biāo)識(shí)符(按那位作者所說)實(shí)際上是“對(duì)象引用”拴疤。并且他接著說任何事物都是“按值傳遞”的。也許有人會(huì)贊成這種精準(zhǔn)卻讓人費(fèi)解的解釋独泞,但我認(rèn)為我的這種方法可以簡(jiǎn)化概念上的理解并且不會(huì)傷害到任何事物呐矾。

對(duì)于基本類型(int等)沒用爭(zhēng)議,肯定是值傳遞懦砂。但String凫佛、基本類型的封裝類(Integer等)、自定義類(如User等)傳遞的是一個(gè)地址孕惜,這就容易讓人聯(lián)想到C++中的指針傳遞和引用傳遞愧薛。以一個(gè)User類為例:

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

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

    // ......

    // 省略了無(wú)參構(gòu)造函數(shù)、所有set/get函數(shù)衫画。

    // ......

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", height=" + height+'\'' +
                ", address=" + super.toString() +
                '}';
    }
}

示例1:

public class MainDemo {
    public static void main(String[] args) {
        User a = new User("a",10,10);
        User b = new User("b",11, 11);
        PrintUtill.println("交換前:");
        PrintUtill.println("a: "+a);
        PrintUtill.println("b: "+b);
        PrintUtill.printlnRule();
        swap(a,b);
        PrintUtill.println("交換最后:");
        PrintUtill.println("a: "+a);
        PrintUtill.println("b: "+b);
        PrintUtill.printlnRule();
        change(a);
        PrintUtill.println("修改最后:");
        PrintUtill.println("a: "+a);
    }

    public static void swap(Object sa, Object sb){
        Object sc = sa;
        sa = sb;
        sb = sc;
        PrintUtill.println("交換中:");
        PrintUtill.println("sa: " + sa);
        PrintUtill.println("sb: " + sb);
        PrintUtill.printlnRule();
    }


}

結(jié)果

交換前:
a: User{name='a', age=10, height=10', address=Others.base.common.User@2503dbd3}
b: User{name='b', age=11, height=11', address=Others.base.common.User@4b67cf4d}

--------windcoder.com----------

交換中:
sa: User{name='b', age=11, height=11', address=Others.base.common.User@4b67cf4d}
sb: User{name='a', age=10, height=10', address=Others.base.common.User@2503dbd3}

--------windcoder.com----------

交換最后:
a: User{name='a', age=10, height=10', address=Others.base.common.User@2503dbd3}
b: User{name='b', age=11, height=11', address=Others.base.common.User@4b67cf4d}

--------windcoder.com----------

不管是斷點(diǎn)跟蹤還是最終打印出的結(jié)果毫炉,swap方法中確實(shí)做了交換(sa和sb的地址做了交換),但并未對(duì)方法外有任何影響(a和b的地址指向依舊是原來(lái)的未變)削罩。

每個(gè)方法的運(yùn)行都會(huì)在Java虛擬機(jī)棧中創(chuàng)建一個(gè)棧幀瞄勾,里面存放了局部變量表等內(nèi)容,方法的運(yùn)行就是一個(gè)棧幀進(jìn)棧出棧的過程弥激。

如方法swap:

public static void swap(Object sa, Object sb)

此時(shí)的sa,sb屬于形參进陡,就是形式參數(shù),用于定義方法的時(shí)候使用的參數(shù)微服,用來(lái)接收調(diào)用者傳遞的參數(shù)趾疚。形參只有在方法被調(diào)用的時(shí)候,虛擬機(jī)才會(huì)分配內(nèi)存單元,在方法調(diào)用結(jié)束之后便會(huì)釋放所分配的內(nèi)存單元糙麦。

相關(guān)知識(shí):
JVM-Java內(nèi)存區(qū)域
JVM基礎(chǔ)小結(jié)

換種說法辛孵,當(dāng)調(diào)用swap方法時(shí),sa類似C++中的引用赡磅,成為地址2503dbd3的一個(gè)別名魄缚,亦既上面關(guān)于《思想》中的引用說的更接近引用而不是指針,不同之處是一旦執(zhí)行sa = sb;焚廊,改變的僅是是sa的指向冶匹,對(duì)原地址2503dbd3不會(huì)造成任何影響。一旦方法執(zhí)行完咆瘟,sa被分配到內(nèi)存單元便會(huì)被釋放徙硅。該實(shí)例執(zhí)行如圖:

image.png

示例2:

在示例1中追加代碼后如下:

public class MainDemo {
    public static void main(String[] args) {
        User a = new User("a",10,10);
        User b = new User("b",11, 11);
        // ......
        // 省略示例1中的代碼
        // ......
        change(a);
        PrintUtill.println("修改最后:");
        PrintUtill.println("a: "+a);
    }
    public static void swap(Object sa, Object sb){
        
        // ...省略
        
    }
    public static void change(User sa){
        sa.setName("a2");
        sa.setAge(11);
        sa.setHeight(12);
        PrintUtill.println("修改中:");
        PrintUtill.println("sa: " + sa);
    }
}

結(jié)果

// ......
// 省略之前的

交換最后:
a: User{name='a', age=10, height=10', address=Others.base.common.User@2503dbd3}
b: User{name='b', age=11, height=11', address=Others.base.common.User@4b67cf4d}

--------windcoder.com----------

修改中:
sa: User{name='a2', age=11, height=12', address=Others.base.common.User@2503dbd3}
修改最后:
a: User{name='a2', age=11, height=12', address=Others.base.common.User@2503dbd3}

此時(shí)函數(shù)內(nèi)發(fā)生了變化影響到函數(shù)外的數(shù)據(jù),change方法外的a和方法的參數(shù)sa指向的均是地址2503dbd3搞疗,指向未發(fā)生變化嗓蘑,但函數(shù)中的操作導(dǎo)致所指向的地址2503dbd3中的內(nèi)容發(fā)生了變化,

示例3

public class ListDemo {
    public static void main(String[] args) {
        List<String> list = null;
        // List<String>  list = new ArrayList<String>();
        add(list);
        list.add("3");
        list.add("4");
        PrintUtill.println("list.size:" + list.size());
    }

    public static void add(List<String> list){
        if (list==null){
            list = new ArrayList<String>();
        }
        list.add("1");
        list.add("2");
    }
}

該示例中l(wèi)ist最開始為null匿乃,意味著沒有地址桩皿,當(dāng)作為實(shí)參傳進(jìn)add方法中,add.list沒有地址幢炸,從而執(zhí)行了list = new ArrayList<String>();泄隔,add.list被分配了新的地址,當(dāng)執(zhí)行完add方法宛徊,add.list就會(huì)被釋放佛嬉,但main.list仍舊為空,從而導(dǎo)致NullPointerException(空指針異常)闸天。

擴(kuò)展

C++中函數(shù)參數(shù)的幾種類型:

image.png

參考地址

Java 中的參數(shù)傳遞和引用類型

C++ 函數(shù)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末暖呕,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子苞氮,更是在濱河造成了極大的恐慌湾揽,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,591評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件笼吟,死亡現(xiàn)場(chǎng)離奇詭異库物,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)贷帮,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門戚揭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人撵枢,你說我怎么就攤上這事民晒【樱” “怎么了?”我有些...
    開封第一講書人閱讀 162,823評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵镀虐,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我沟绪,道長(zhǎng)刮便,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,204評(píng)論 1 292
  • 正文 為了忘掉前任绽慈,我火速辦了婚禮恨旱,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘坝疼。我一直安慰自己搜贤,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,228評(píng)論 6 388
  • 文/花漫 我一把揭開白布钝凶。 她就那樣靜靜地躺著仪芒,像睡著了一般。 火紅的嫁衣襯著肌膚如雪耕陷。 梳的紋絲不亂的頭發(fā)上掂名,一...
    開封第一講書人閱讀 51,190評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音哟沫,去河邊找鬼饺蔑。 笑死,一個(gè)胖子當(dāng)著我的面吹牛嗜诀,可吹牛的內(nèi)容都是我干的猾警。 我是一名探鬼主播,決...
    沈念sama閱讀 40,078評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼隆敢,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼发皿!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起拂蝎,我...
    開封第一講書人閱讀 38,923評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤雳窟,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后匣屡,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體封救,經(jīng)...
    沈念sama閱讀 45,334評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,550評(píng)論 2 333
  • 正文 我和宋清朗相戀三年捣作,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了誉结。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,727評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡券躁,死狀恐怖惩坑,靈堂內(nèi)的尸體忽然破棺而出掉盅,到底是詐尸還是另有隱情,我是刑警寧澤以舒,帶...
    沈念sama閱讀 35,428評(píng)論 5 343
  • 正文 年R本政府宣布趾痘,位于F島的核電站,受9級(jí)特大地震影響蔓钟,放射性物質(zhì)發(fā)生泄漏永票。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,022評(píng)論 3 326
  • 文/蒙蒙 一滥沫、第九天 我趴在偏房一處隱蔽的房頂上張望侣集。 院中可真熱鬧,春花似錦兰绣、人聲如沸世分。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)臭埋。三九已至,卻和暖如春臀玄,著一層夾襖步出監(jiān)牢的瞬間斋泄,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工镐牺, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留炫掐,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,734評(píng)論 2 368
  • 正文 我出身青樓睬涧,卻偏偏與公主長(zhǎng)得像募胃,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子畦浓,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,619評(píng)論 2 354

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

  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對(duì)...
    cosWriter閱讀 11,097評(píng)論 1 32
  • 在一個(gè)方法內(nèi)部定義的變量都存儲(chǔ)在棧中痹束,當(dāng)這個(gè)函數(shù)運(yùn)行結(jié)束后,其對(duì)應(yīng)的棧就會(huì)被回收讶请,此時(shí)祷嘶,在其方法體中定義的變量將不...
    Y了個(gè)J閱讀 4,416評(píng)論 1 14
  • 一:java概述: 1,JDK:Java Development Kit夺溢,java的開發(fā)和運(yùn)行環(huán)境论巍,java的開發(fā)...
    慕容小偉閱讀 1,788評(píng)論 0 10
  • 整理來(lái)自互聯(lián)網(wǎng) 1,JDK:Java Development Kit风响,java的開發(fā)和運(yùn)行環(huán)境嘉汰,java的開發(fā)工具...
    Ncompass閱讀 1,537評(píng)論 0 6
  • 01 上周日的晚上,當(dāng)上三年級(jí)的兒子把數(shù)學(xué)考試卷拿給家長(zhǎng)簽字的時(shí)候状勤,我情緒失控了鞋怀。我看到考試卷上赫然寫著一個(gè)紅紅的...
    藍(lán)莓書閱讀 392評(píng)論 0 1