日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

JAVA 方法調用中的參數是值傳遞還是引用傳遞呢?相信每個做開發的同學都碰到過傳這個問題,不光是做 Java 的同學,用 C#、Python 開發的同學同樣肯定遇到過這個問題,而且很有可能不止一次。

那么,Java 中到底是值傳遞還是引用傳遞呢,答案是值傳遞,Java 中沒有引用傳遞這個概念。

數據類型和內存分配

Java 中有可以概括為兩大類數據類型,一類是基本類型,另一類是引用類型。

基本類型

byte、short、int、long、float、double、char、boolean 是 Java 中的八種基本類型。基本類型的內存分配在棧上完成,也就是 JVM 的虛擬機棧。也就是說,當你使用如下語句時:

int i = 89;

會在虛擬機棧上分配 4 個字節的空間出來存放。

引用類型

引用類型有類、接口、數組以及 null 。我們平時熟悉的各種自定義的實體類啊就在這個范疇里。

當我們定義一個對象并且使用 new 關鍵字來實例化對象時。

User user = new User();

會經歷如下三個步驟:

1、聲明一個引用變量 user,在虛擬機棧上分配空間;

2、使用 new 關鍵字創建對象實例,在堆上分配空間存放對象內的屬性信息;

3、將堆上的對象鏈接到 user 變量上,所以棧上存儲的實際上就是存的對象在堆上的地址信息;

數組對象也是一樣的,棧上只是存了一個地址,指向堆上實際分配的數組空間,實際的值是存在堆上的。

為了清楚的展示空間分配,我畫了一張類型空間分配的示例圖。

難住了同事:Java 方法調用到底是傳值還是傳引用

 

沒有爭議的基本類型

當我們將 8 種基本類型作為方法參數傳遞時,沒有爭議,傳的是什么(也就是實參),方法中接收的就是什么(也就是形參)。傳遞過去的是 1 ,那接到的就是1,傳過去的是 true,接收到的也就是 true。

看下面這個例子,將變量 oldIntValue 傳給 changeIntValue 方法,該方法內對參數值進行修改,最后輸出的結果還是 1。

public static void main( String[] args ) throws Exception{
    int oldIntValue = 1;
    System.out.println( oldIntValue );
    passByValueOrRef.changeIntValue( oldIntValue );
    System.out.println( oldIntValue );
}

public static void changeIntValue( int oldValue ){
    int newValue = 100;
    oldValue = newValue;
}

改變參數值并不會改變原變量的值,沒錯吧,Java 是按值傳遞。

數組和類

數組

有的同學說那不對呀,你看我下面這段代碼,就不是這樣。

public static void main( String[] args ) throws Exception{
    int[] oldArray = new int[] { 1, 2 };
    System.out.println( oldArray[0] );
    changeArrayValue( oldArray );
    System.out.println( oldArray[0] );
}

public static void changeArrayValue( int[] newArray ){
    newArray[0] = 100;
}

這段代碼的輸出是

1
100

說明調用 changeArrayValue 方法時,修改傳過來的數組參數中的第一項后,原變量的內容改變了,那這怎么是值傳遞呢。

別急,看看下面這張圖,展示了數組在 JVM 中的內存分配示例圖。

難住了同事:Java 方法調用到底是傳值還是傳引用

 

實際上可以理解為 changeArrayValue 方法接收的參數是原變量 oldArray 的副本拷貝,只不過數組引用中存的只是指向堆中數組空間的首地址而已,所以,當調用 changeArrayValue 方法后,就形成了 oldArray 和 newArray 兩個變量在棧中的引用地址都指向了同一個數組地址。所以修改參數的每個元素就相當于修改了原變量的元素。

一般我們在開發過程中有很多將類實例作為參數的情況,我們抽象出來的各種對象經常在方法間傳遞。比如我們定義了一個用戶實體類。

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;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + ''' +
                ", age=" + age +
                '}';
    }
}

比方說我們有一個原始的實體 User 類對象,將這個實體對象傳給一個方法,這個方法可能會有一些邏輯處理,比如我們拿到這個用戶的 name 屬性,發現 name 為空,我們就給 name 屬性賦予一個隨機名稱,例如 “用戶398988”。這應該是很常見的一類場景了。

我們通常這樣使用,將 user 實例當做參數傳過來,處理完成后,再將它返回。

public static void main( String[] args ) throws Exception{
    User oldUser = new User( "原始姓名", 8 );
    System.out.println( oldUser.toString() );
    oldUser = changeUserValue( oldUser );
    System.out.println( oldUser.toString() );
}

public static User changeUserValue( User newUser ){
    newUser.setName( "新名字" );
    newUser.setAge( 18 );
  return newUser;
}

但有的同學說,我發現修改完成后就算不返回,原變量 oldUser 的屬性也改變了,比如下面這樣:

public static void main( String[] args ) throws Exception{
    User oldUser = new User( "原始姓名", 8 );
    System.out.println( oldUser.toString() );
    changeUserValue( oldUser );
    System.out.println( oldUser.toString() );
}

public static void changeUserValue( User newUser ){
    newUser.setName( "新名字" );
    newUser.setAge( 18 );
}

返回的結果都是下面這樣

User{name='原始姓名', age=8}
User{name='新名字', age=18}

那這不就是引用傳遞嗎,改了參數的屬性,就改了原變量的屬性。仍然來看一張圖

難住了同事:Java 方法調用到底是傳值還是傳引用

 

實際上仍然不是引用傳遞,引用傳遞我們學習 C++ 的時候經常會用到,就是指針。而這里傳遞的其實是一個副本,副本中只存了指向堆空間對象實體的地址而已。我們我們修改參數 newUser 的屬性間接的就是修改了原變量的屬性。

有同學說,那畫一張圖說這樣就是這樣嗎,你說是副本就是副本嗎,我偏說就是傳的引用,就是原變量,也說得通啊。

確實是說的通,如果真是引用傳遞,也確實是這樣的效果沒錯。那我們就來個反例。

public static void main( String[] args ) throws Exception{
    User oldUser = new User( "原始姓名", 8 );
    System.out.println( oldUser.toString() );
    wantChangeUser( oldUser );
    System.out.println( oldUser.toString() );
}

public static void wantChangeUser( User newUser ){
    newUser = new User( "新姓名", 18 );
}

假設就是引用傳遞,那么 newUser 和 main 方法中的 oldUser 就是同一個引用對象,那我在 wantChangeUser 方法中重新 new 了一個 User 實體,并賦值給了 newUser,按照引用傳遞這個說法,我賦值給了參數也就是賦值給了原始變量,那么當完成賦值操作后,原變量 oldUser 就應該是 name = "新名字"、age=18 才對。

然后,我們運行看看輸出結果:

User{name='原始姓名', age=8}
User{name='原始姓名', age=8}

結果依然是修改前的值,我們修改了 newUser ,并沒有影響到原變量,顯然不是引用傳遞。

結論

Java 中的參數傳遞是值傳遞,并且 Java 中沒有引用傳遞這個概念。我們通常說的引用傳遞,一般都是從 C 語言和 C like 而來,因為它們有指針的概念。

而我們也知道,C、C++ 中需要程序員自己管理內存,而指針的使用經常會導致內存泄漏一類的問題,Java 千辛萬苦的就是為了讓程序員解放出來,而使用垃圾收集策略管理內存,這其中很重要的一點就是規避了指針的使用,所以在 Java 的世界中沒有所謂的指針傳遞。

分享到:
標簽:Java
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定