Java方法參數(shù)是引用調(diào)用還是值調(diào)用?
方法調(diào)用(call by) 是一個(gè)標(biāo)準(zhǔn)的計(jì)算機(jī)科學(xué)術(shù)語(yǔ)。方法調(diào)用根據(jù)參數(shù)傳遞的情況又分為值調(diào)用( call by reference ) 和引用調(diào)用( call by value ) 。江湖上有很多關(guān)于這兩種調(diào)用的定義 ,最通常的說(shuō)法是傳遞值的是值調(diào)用,傳遞地址的是引用調(diào)用。這其實(shí)很不恰當(dāng),這種 這些說(shuō)法很容易讓我們聯(lián)想到Java的對(duì)象參數(shù)傳遞是引用調(diào)用,實(shí)際上,Java的對(duì)象參數(shù)傳遞仍然是值調(diào)用 。
我們首先用一段代碼來(lái)證實(shí)一下為什么Java的對(duì)象參數(shù)傳遞是值調(diào)用。
public class Employee {
public String name=null;
public Employee(String n){
this.name=n;
}
//將兩個(gè)Employee對(duì)象交換
public static void swap(Employee e1,Employee e2){
Employee temp=e1;
e1=e2;
e2=temp;
System.out.println(e1.name+" "+e2.name); //打印結(jié)果:李四 張三
}
//主函數(shù)
public static void main(String[] args) {
Employee worker=new Employee("張三");
Employee manager=new Employee("李四");
swap(worker,manager);
System.out.println(worker.name+" "+manager.name); //打印結(jié)果仍然是: 張三 李四
}
}
上面的結(jié)果讓人很失望,雖然形參對(duì)象e1,e2的內(nèi)容交換了,但實(shí)參對(duì)象worker,manager并沒(méi)有互換內(nèi)容。這里面最重要的原因就在于形參e1,e2是實(shí)參worker,manager的地址拷貝。
大家都知道,在Java中對(duì)象變量名實(shí)際上代表的是對(duì)象在堆中的地址(專業(yè)術(shù)語(yǔ)叫做對(duì)象引用 )。在Java方法調(diào)用的時(shí)候,參數(shù)傳遞的是對(duì)象的引用。重要的是,形參和實(shí)參所占的內(nèi)存地址并不一樣,形參中的內(nèi)容只是實(shí)參中存儲(chǔ)的對(duì)象引用的一份拷貝。
如果大家對(duì)JVM內(nèi)存管理中Java棧 的局部變量區(qū) 有所了解的話(可以參見(jiàn)《 Java 虛擬機(jī)體系結(jié)構(gòu) 》),就很好理解上面這句話。在JVM運(yùn)行上面的程序時(shí),運(yùn)行main方法和swap方法,會(huì)在Java棧中先后push兩個(gè)叫做棧幀 的內(nèi)存空間。main棧幀中有一塊叫局部變量區(qū)的內(nèi)存用來(lái)存儲(chǔ)實(shí)參對(duì)象worker和manager的引用。而swap棧幀中的局部變量區(qū)則存儲(chǔ)了形參對(duì)象e1和e2的引用。雖然e1和e2的引用值分別與worker和manager相同,但是它們占用了不同的內(nèi)存空間。當(dāng)e1和e2的引用發(fā)生交換時(shí),下面的圖很清晰的看出完全不會(huì)影響worker和manager的引用值。

Java對(duì)象參數(shù)傳遞雖然傳遞的是地址(引用),但仍然是值調(diào)用。是時(shí)候需要給引用調(diào)用和值調(diào)用一個(gè)準(zhǔn)確的定義了。
值調(diào)用(call by value): 在參數(shù)傳遞過(guò)程中,形參和實(shí)參占用了兩個(gè)完全不同的內(nèi)存空間。形參所存儲(chǔ)的內(nèi)容是實(shí)參存儲(chǔ)內(nèi)容的一份拷貝。實(shí)際上,Java對(duì)象的傳遞就符合這個(gè)定義,只不過(guò)形參和實(shí)參所儲(chǔ)存的內(nèi)容并不是常規(guī)意義上的變量值,而是變量的地址???,回過(guò)頭想想:變量的地址不也是一種值嗎!
引用調(diào)用(call by reference) : 在參數(shù)傳遞的過(guò)程中,形參和實(shí)參完全是同一塊內(nèi)存空間,兩者不分彼此。 實(shí)際上,形參名和實(shí)參名只是編程中的不同符號(hào),在程序運(yùn)行過(guò)程中,內(nèi)存中存儲(chǔ)的空間才是最重要的。不同的變量名并不能說(shuō)明占用的內(nèi)存存儲(chǔ)空間不同。
大體上說(shuō),兩種調(diào)用的根本并不在于傳遞的是值還是地址(畢竟地址也是一個(gè)值),而是在于形參和實(shí)參是否占用同一塊內(nèi)存空間。事實(shí)上,C/C++的指針參數(shù)傳遞也是值調(diào)用,不信試試下面的C代碼吧!
#include<stdio.h>
void swap(int *a1,int *b1){
int *t=a1;
a1=b1;
b1=t;
}
int main(){
int x1=100;
int x2=200;
int *a=&x1;
int *b=&x2;
printf("%d %d\n",*a,*b);
swap(a,b);
printf("%d %d\n",*a,*b);
return 0;
}
但C/C++是有引用調(diào)用的,這就是C/C++一種叫做引用的變量聲明方法: int a; int &ra=a; 其中ra是a的別名,兩者在內(nèi)存中沒(méi)有區(qū)別,占用了同一個(gè)內(nèi)存空間。而通過(guò)引用(別名)的參數(shù)傳遞就符合引用調(diào)用的特點(diǎn)了。大家可以去試試void swap(int &a1,int &b1);的運(yùn)行結(jié)果。
通過(guò)本文大家應(yīng)該知道Java方法參數(shù)是引用調(diào)用還是值調(diào)用了吧。
相關(guān)文章
基于Java中進(jìn)制的轉(zhuǎn)換函數(shù)詳解
下面小編就為大家?guī)?lái)一篇基于Java中進(jìn)制的轉(zhuǎn)換函數(shù)詳解。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-07-07
idea運(yùn)行程序報(bào)錯(cuò)java程序包org.junit不存在解決辦法
這篇文章主要給大家介紹了關(guān)于idea運(yùn)行程序報(bào)錯(cuò)java程序包org.junit不存在的解決辦法, 當(dāng)出現(xiàn)程序包org.junit不存在的問(wèn)題時(shí),可以通過(guò)使用適當(dāng)?shù)腏Unit版本、添加依賴或重新下載程序包等方式進(jìn)行解決,需要的朋友可以參考下2024-02-02
Java中Lambda表達(dá)式之Lambda語(yǔ)法與作用域解析
這篇文章主要介紹了Java中Lambda表達(dá)式之Lambda語(yǔ)法與作用域解析重點(diǎn)介紹Lambda表達(dá)式基礎(chǔ)知識(shí),需要的朋友可以參考下2017-02-02
Spring Boot整合RabbitMQ開(kāi)發(fā)實(shí)戰(zhàn)詳解
這篇文章主要介紹了Spring Boot整合RabbitMQ開(kāi)發(fā)實(shí)戰(zhàn),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-02-02
springboot + mybatis-plus實(shí)現(xiàn)多表聯(lián)合查詢功能(注解方式)
這篇文章主要介紹了springboot + mybatis-plus實(shí)現(xiàn)多表聯(lián)合查詢功能,是最簡(jiǎn)單的一種注解方式,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-09-09
解決IDEA使用Spring Initializr創(chuàng)建項(xiàng)目時(shí)無(wú)法連接到https://start.spring.io的問(wèn)
這篇文章主要介紹了解決IDEA使用Spring Initializr創(chuàng)建項(xiàng)目時(shí)無(wú)法連接到https://start.spring.io的問(wèn)題,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-04-04
itextpdf提取PDF文件中的任意頁(yè)碼實(shí)現(xiàn)示例
這篇文章主要為大家介紹了itextpdf提取PDF文件中的任意頁(yè)碼實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08
Springboot整合Java?DL4J實(shí)現(xiàn)交通標(biāo)志識(shí)別系統(tǒng)全過(guò)程
在自動(dòng)駕駛系統(tǒng)中,交通標(biāo)志識(shí)別是實(shí)現(xiàn)車輛智能化的關(guān)鍵技術(shù)之一,本文介紹了利用SpringBoot和JavaDeeplearning4j構(gòu)建交通標(biāo)志識(shí)別系統(tǒng)的方法,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-10-10
Java web實(shí)現(xiàn)動(dòng)態(tài)圖片驗(yàn)證碼的示例代碼
這篇文章主要介紹了Java web實(shí)現(xiàn)動(dòng)態(tài)圖片驗(yàn)證碼的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-01-01

