java中傳值方式的我的理解

前言

這幾天在整理java基礎知識方面的內容,對於值傳遞還不是特別理解,因而查閱了一些資料和網上相關博客,本身進行了概括總結,最後將其整理成了一篇博客。java

值傳遞

值傳遞是指在調用函數時將實際參數複製一份傳遞給形參,這樣在函數中對形參的修改將不會影響到實際參數的值。函數

引用傳遞

引用傳遞是指在調用函數時將實際參數的地址直接傳遞到形參,那麼在函數中對參數所進行的修改,將會影響到實際參數的值。測試

咱們可使用一段程序來驗證Java中只有值傳遞this

/**
 * 驗證java中只有值傳遞
 * Dmego 2018-8-27
 */

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

public class TestValue {
    public static void change(User user2,int a2){
        System.out.println("改變以前:"+user2.getName()+",a2="+a2);
        
        user2.setName("李四"); //改變 user2 的 name 值
        a2 = 10; //改變 a2 的值
        System.out.println("改變以後:"+user2.getName()+",a2="+a2);
        
        user2 = new User(); //將 user2 從新指向一個新對象
        user2.setName("王五");
        System.out.println("從新指向一個新對象後:"+user2.getName());
    }

    public static void main(String[] args){
        User user1 = new User();
        user1.setName("張三"); //初始化 user1 的 name 爲張三
        int a1 = 5; //初始化 a1 的值爲 5
        change(user1,a1); //調用方法驗證傳值方式
        System.out.println("調用方法後:"+user1.getName()+",a1="+a1);
    }
}

運行這段程序,輸出結果爲:spa

改變以前:張三,a2=5
改變以後:李四,a2=10
從新指向一個新對象後:王五
調用方法後:李四,a1=5

結果分析

堆與內存分析

下面咱們以上圖爲輔助,來分析這段程序,首先咱們定義了一個User類,而後在測試類中實例化了一個User對象,名爲user1,而且爲其賦值name = '張三',此時在內存中如圖1所示,實例化一個對象至關於在堆中開闢了一塊內存,內存地址爲017,此時這個對象的引用爲user1,內存地址爲001,它保存了該對象在內存中的地址,也就是指向了該對象。接下了,咱們調用方法change(),來嘗試改變user1name值以此驗證java中的傳值方式。code

咱們將user1做爲實參傳給change()方法,形參user2來接受這個實參,在這裏就體現出了兩種傳參方式的不一樣。若是是按值傳遞,那麼就像定義的那樣,如圖2所示,user2user1的一份副本,也就是說在傳遞參數時,將user1(自己是一個對象的引用),複製了一份,名爲user2,它一樣也是一個對象的引用,而且user1user2此時指向同一個對象。而若是是引用傳遞,也如同定義的那樣,如圖5所示,在傳遞參數時,是直接將user1傳遞給了形參,只是換了一個名字叫作user2,可是本質上user1user2實際上是同一個。它是一個對象的引用。對象

接着來分析輸出的結果,不論是按值傳遞仍是引用傳遞,第1行輸出的結果必定都是張三,由於都是指向同一個對象。對於第2行輸出,咱們仍是沒法判斷是哪一種方式,由於都是改變同一個對象,值也會改變;關鍵在於第3行輸出和第4行輸出,此時,咱們將user2從新指向了一個新的對象,而且爲這個對象賦值name = '王五',若是是引用傳遞的方式,那麼user1一樣也會改變指向,指向新的這個對象,最後一行調用方法以後輸出的結果將會和第3行同樣是王五,可是事實輸出的是李四,這代表user1user2其實並非同一個。真實的調用過程如 圖2~圖4所示,這樣纔會使得user2指向一個新的對象後,user1指向的對象並無改變,仍是原來那個對象。內存

對於基本類型的參數來講,a1的值最後沒有改變,說明在執行方法時,a2a1的一個副本。對於引用類型的參數來講,例如User對象,在調用方法時,其實是將其引用user1做爲實際參數,那麼傳遞給形參的將是該引用的一份副本引用user2,雖說這是兩份引用(比如a1a2的關係)。可是卻指向同一個對象,全部的操做也都是對這同一個對象而言的。get

最後舉一個例子來形象的說明這一切,假如你有一把你房間的鑰匙,而且在上面刻上了你的名字,這個過程比如給一個int類型的a1初始化值爲5。你的朋友和你關係很是好,想要你房間的鑰匙,此時你並無直接把你的鑰匙給他,而是複製了一把新的鑰匙,這個鑰匙也能開你的房間的門。而你的朋友在這把新鑰匙上刻上了他的名字。這個過程就比如調用change()方法,把a1複製了一份賦值給a2,此時修改a2a1沒有任何關係,你朋友在新鑰匙上刻他名字也不會影響你手上那把原始的鑰匙。關鍵是這兩把鑰匙都能開你的房間,就比如user1user2都指向同一個對象。此時你朋友用這把新鑰匙打開了你的房間,將你房間電視機砸了。這個過程比如更名李四。這時你拿着你的鑰匙打開你房間必然會看到這樣的場景——電視機被砸了。就如同調用方法後user1變成了李四。在調用方法的過程當中,最後user2從新指向了一個新的對象,這就比如你的朋友將你複製給他的鑰匙再次進行了加工,此時不能開你房間的門,可是能開他本身的房間,他用這把鑰匙開本身的房間而後把本身的電視砸了這並不會影響到你房間的電視,也就是說最後user1的名字並不會變成王五。這就是java中的值傳遞。固然了,若是是引用傳遞,那麼這個例子中從頭至尾將會只有一把鑰匙,最後的結果也將會不一樣。博客

尾聲

經過以上分析咱們能夠知道。Java中只有值傳遞這一種方式,只不過對於引用類型來講,傳遞的參數是對象的引用罷了。

相關文章
相關標籤/搜索