如何理解Java中參數傳遞只能傳值?

來源:互聯網
上載者:User

標籤:

以前學習C#的時候,是完全在工作崗位上學習,一些底層較為深入的道理都不是很清楚。如今學習了Java,對於Java參數傳遞只能傳值,不能傳引用(指標)感到很困惑,在C#中不是常常說把某個引用傳遞到函數中嗎?甚至C#有相當簡便的ref、out參數,明明白白的傳引用。

經過一番探索,得出的結論表明,Java中我不管你到底是傳值還是傳引用,只需要記住原生資料類型(實值型別)和String作為參數傳遞的時候,其原本的值都不會發生改變;而參考型別在作為參數傳遞時,函數中對其的操作,都會反饋到引用所指向的值。

這個結論不是和C#一模一樣嘛,除了C#可以方便的使用ref、out以外……

下面對Java中參數傳遞只能傳值進行解釋,事實證明,以前我對於C#的傳值還是傳引用理解的也不夠深入:

先申明:java中的參數傳遞都是值傳遞,沒有引用傳遞。
值傳遞的概念:值傳遞會為所傳遞的對象(這裡的對象不是java裡的對象object,而是一般意義上的對象)重新開闢一塊空間,於是對所傳對象的操作不會影響到原對象。
現象:有種說法是java中基礎資料型別 (Elementary Data Type)作參數是值傳遞,對象做參數是引用傳遞。實際上是錯誤的,真正的引用傳遞,是類似C語言中的指標傳遞,和C#中的ref參數。
理解:為什麼對象做參數也是值傳遞呢?
分析:對象做參數傳遞的是對象的引用,暫且可以理解成對象的地址。由於是值傳遞,那麼被傳遞的對象本身是不會有任何變化的,所以該對象的引用是不會發生任何變化的。

 

1、先舉一個原生資料類型的例子:

測試函數:

    public static void ValueTrans(int a){        a = 2;//新產生一個值,開闢一個實值型別出來,故值不會被修改。    }

測試此函數的代碼:

        int a = 1;        System.out.println("a‘s value(before) = " + a);        ValueTrans(a);        System.out.println("a‘s value(after) = " + a);

列印出的結果:

a‘s value(before) = 1a‘s value(after) = 1

安裝Java值傳遞的思想來考慮,這個結果是顯而易見的,pass by value,我只是把這個數值傳給你使用。

2、那麼Integer如何理解呢?

測試函數:

    public static void ValueTrans2(Integer a){        a = new Integer(2);    }


其中a也是一個對象,那麼這麼傳入,是不是傳引用呢?調用了這個函數,a的int值會不會被修改呢?

測試此函數的代碼:

        Integer a2 = new Integer(1);        System.out.println("a2‘s value(before) = " + a2);        ValueTrans2(a2);        System.out.println("a2‘s value(after) = " + a2);

列印出的結果:

a2‘s value(before) = 1a2‘s value(after) = 1

結果表明,值仍舊沒有被修改。

如何解釋這個現象:

    理解這裡的關鍵是區分對象和引用。這裡聲明的a2是一個引用,而不是一個對象(只是Java把它設計為看上去好像是對象一樣)。這個引用它指向了一個對象,這個對象就是後面用new關鍵字產生的對象。因此,可以說a2指向了一個Integer對象。
    在調用ValueTrans2方法的時候,程式將a2作為參數傳遞給ValueTrans2方法了。這裡仍然是值傳遞,在ValueTrans2調用過程中,會產生一份新的引用(不妨叫做y)。此時,a2和y指向了同一個對象。

    但是此時,我們讓y指向另外一個對象, y=new Integer(2); 此時a2和y就指向了不同的對象。y修改了它指向的對象的屬性,很顯然不會影響到a2指向的對象。

    (這裡不妨說明一下參考型別的傳遞,如我把一個參考型別x傳入函數中,這裡也是值傳遞,在函數被調用的過程中,產生了一個新的引用y,x和y指向同一個對象。此時修改y指向的對象,也即修改x所指向的對象!那麼參考型別的傳遞,會造成x所指向的值被修改)

圖解如下:

3、如何理解String?

如果你理解了2當中Integer的傳遞方式,那麼我想String也不難理解。我們建立一個String,

String string = "old String";


實際上就是

String string2 = new String("old String");

Java的機制,造成當你使用一個String如"old String"時,會建立一個對象出來。

本著負責任的態度,仍舊把相應的測試函數貼上來:

    public static void StringTrans(String string){        string = "new String";    }

測試函數的代碼:

        String string = "old String";        System.out.println("string‘s value(before) = " + string);        StringTrans(string);        System.out.println("string‘s value(after) = " + string);

列印出的結果:

string‘s value(before) = old Stringstring‘s value(after) = old String

原因就是,實際上函數StringTrans是複製了一個引用指向原來的對象,但是函數又讓這個引用指向了新的String對象。這不會對原來的引用和原來的對象造成任何影響!

4、如何理解參考型別是傳值?

測試自訂類:

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

測試的函數:

    public static void ReferTrans(People people){        people.age = 2;        people.name = "lisi";    }

測試函數的代碼:

        People people = new People(1, "zhangsan");        System.out.println("people‘s age(before) = " + people.age);        System.out.println("people‘s name(before) = " + people.name);        ReferTrans(people);        System.out.println("people‘s age(after) = " + people.age);        System.out.println("people‘s name(after) = " + people.name);

列印的結果:

people‘s age(before) = 1people‘s name(before) = zhangsanpeople‘s age(after) = 2people‘s name(after) = lisi

設建立的對象是PEOPLE,其引用是people,在調用ReferTrans方法是,仍然是值傳遞,方法賦值了一個引用people2,people2仍舊指向PEOPLE,所以操作people2對對象進行修改,即為對PEOPLE進行修改(String的話在此時已經new了一個新對象出來),和使用people的效果一樣。表現出現來現象就是,當參考型別傳入函數時,函數中對其的修改,都會表現在原來的參考型別上。

圖解如下:

 

我一直認為只給分析過程,不給結論的都是耍流氓的行為。

結論

1、在實際的使用過程中,我們不必糾結那麼多,原生資料類型和String,在傳入函數的時候,不管函數裡面做什麼,他的值都不會被修改。參考型別傳遞到函數中,只要函數中不是讓參數指向一個建立的對象,那麼函數中的修改會反映到此參考型別上。

2、平時的處理上,可以把String和原生資料類型放在同一類的情況下使用,因為Java內部使用了很多的機制,讓String看起來跟原生資料類型一樣。但是String歸根結底是一個參考型別,如在進行比較時,其他原生資料類型可以使用==,而String必須使用equals方法才能比較其內部的值(這點C#做的非常好,直接使用==,不讓程式員過分的瞭解底層,我在做C#編程的過程中,甚至從來都沒有覺得string和實值型別有什麼不同)。

3、Java確實是只能傳值,不能傳引用。所謂傳引用,只在C、C++的傳指標和C#的ref中存在。

 

如何理解Java中參數傳遞只能傳值?

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.