一文了解為什么Java中只有值傳遞
經(jīng)典的問(wèn)題
Java 傳參是值傳遞還是引用傳遞?這個(gè)問(wèn)題很基礎(chǔ),但是許多人都有點(diǎn)懵
形參&實(shí)參
首先我們得了解關(guān)于參數(shù)的幾個(gè)概念
形式參數(shù):定義函數(shù)時(shí)使用的參數(shù),用來(lái)接收函數(shù)傳入?yún)?shù),比如我們寫(xiě)個(gè)函數(shù),函數(shù)中的參數(shù)為形式參數(shù)
public void test(String str) { //str為形式參數(shù)
System.out.println(str);
}
實(shí)際參數(shù):我們調(diào)用函數(shù)時(shí),函數(shù)名后面括號(hào)中的參數(shù)稱為實(shí)際參數(shù),必須有確定的值,如下面例子所示
public static void main(String[] args) {
A a = new A();
a.test("小 明"); //"小 明"則為實(shí)際參數(shù)
}
可以發(fā)現(xiàn),當(dāng)調(diào)用一個(gè)有參函數(shù)的時(shí)候,會(huì)把實(shí)際參數(shù)傳遞給形式參數(shù)。
這種傳遞的過(guò)程的參數(shù)一般有2種情況值傳遞和引用傳遞。
- 值傳遞:調(diào)用函數(shù)時(shí)將實(shí)際參數(shù)復(fù)制一份傳遞到函數(shù)中,函數(shù)內(nèi)部對(duì)參數(shù)內(nèi)部進(jìn)行修改不會(huì)影響到實(shí)際參數(shù),即創(chuàng)建副本,不會(huì)影響原生對(duì)象
- 引用傳遞 :方法接收的是實(shí)際參數(shù)所引用的地址,不會(huì)創(chuàng)建副本,對(duì)形參的修改將影響到實(shí)參,即不創(chuàng)建副本,會(huì)影響原生對(duì)象
我們還得知道:在Java中有2種數(shù)據(jù)類型,其中主要有基本數(shù)據(jù)類型和引用數(shù)據(jù)類型,除了8種基本數(shù)據(jù)類型以外都是引用數(shù)據(jù)類型,分別是byte,short,int,long,char,boolean,float,double
Java是值傳遞還是引用傳遞
對(duì)于這個(gè)問(wèn)題,我們先來(lái)看幾個(gè)例子慢慢道來(lái):
傳參的類型:基本數(shù)據(jù)類型
public class TestBasic {
public static void main(String[] args) {
int num1 = 10;
int num2 = 20;
change(num1, num2);
System.out.println("==============");
System.out.println("num1 = " + num1);
System.out.println("num2 = " + num2);
}
public static void change(int param1, int param2) {
System.out.println("param1 = " + param1);
System.out.println("param2 = " + param2);
param1 = 333;
param2 = 444;
System.out.println("after change....");
System.out.println("param1 = " + param1);
System.out.println("param2 = " + param2);
}
}
結(jié)果:
param1 = 10
param2 = 20
after change....
param1 = 333
param2 = 444
==============
num1 = 10
num2 = 20
我們可以發(fā)現(xiàn),change()方法內(nèi)對(duì)變量重新賦值,并未改變變量num1和num2的值,改變的只是change()方法內(nèi)的num1和num2的副本。我們需要知道,基本數(shù)據(jù)類型在內(nèi)存中只有一塊存儲(chǔ)空間,分配在棧stack中。
Java傳參的類型如果是基本數(shù)據(jù)類型,是值傳遞。

傳參的類型:引用數(shù)據(jù)類型
public class TestQuote {
public static void main(String[] args) {
String str = "小明";
StringBuilder str2 = new StringBuilder("今天天氣好");
change(str,str2);
System.out.println("==============");
System.out.println("str = " + str);
System.out.println("str2 = " + str2);
}
public static void change(String param1,StringBuilder param2) {
System.out.println("param1 = " + param1);
System.out.println("param2 = " + param2);
param1= "小張";
param2.append(",我們?nèi)メ烎~(yú)");
System.out.println("after change....");
System.out.println("param1 = " + param1);
System.out.println("param2 = " + param2);
}
}
結(jié)果:
param1 = 小明
param2 = 今天天氣好
after change....
param1 = 小張
param2 = 今天天氣好,我們?nèi)メ烎~(yú)
str = 小明
str2 = 今天天氣好,我們?nèi)メ烎~(yú)
我們發(fā)現(xiàn)str變量沒(méi)有改變,但是str2變量卻改變了,大家是不是迷惑了:Java傳參的類型如果是引用數(shù)據(jù)類型,是值傳遞還是引用傳遞?

其實(shí)大家被一堆術(shù)語(yǔ)給忽悠了,筆者畫(huà)了2張圖,幫助大家理解:
before change():

after change():

在Java中,除了基本數(shù)據(jù)類型以外,其他的都是引用類型,引用類型在內(nèi)存中有兩塊存儲(chǔ)空間(一塊在棧stack中,一塊在堆heap中)。
如果參數(shù)是引用類型,傳遞的就是實(shí)參所引用的對(duì)象在棧中地址值的拷貝,這里創(chuàng)建的副本是 地址的拷貝。那就有人說(shuō)了,可是它值變了呀,這明明就是"引用傳遞"嘛?
我們可以換個(gè)角度理解,如果我們把棧地址當(dāng)成值,會(huì)創(chuàng)建棧地址副本(復(fù)制棧幀),棧地址最終并沒(méi)有改變,改變的是堆內(nèi)存中的值。這就好比棧地址是鑰匙,我們copy了一把,它能打開(kāi)保險(xiǎn)箱。我們關(guān)心的是鑰匙有沒(méi)有花紋這種變化,至于打開(kāi)保險(xiǎn)箱后的錢多錢少,我們并不需要關(guān)心。
雖然調(diào)用完函數(shù)后,str2變量值(堆中的數(shù)據(jù))改變了,但是參數(shù)是引用類型,傳遞的實(shí)參是 棧中地址值,這是我們關(guān)心的,拷貝的是棧中地址值,最終棧中地址值并沒(méi)有改變。所以是符合值傳遞的定義創(chuàng)建副本,不會(huì)影響原生對(duì)象。
可能又有人問(wèn)了,那str變量值為啥沒(méi)有改變呢?其實(shí)這完全是由于String類的特殊,我們知道它是不可變的final,這個(gè)時(shí)候在函數(shù)中 param1= "小張";其實(shí)會(huì)隱式創(chuàng)建一個(gè)新的String對(duì)象,同時(shí)堆內(nèi)存中會(huì)開(kāi)辟一個(gè)新的內(nèi)存空間,param1指向了這個(gè)新開(kāi)辟的內(nèi)存空間。原地址str指向的堆內(nèi)存空間中數(shù)據(jù)沒(méi)有任何改變。
尾語(yǔ)
Java中只有值傳遞,始終是傳值的,我們要牢記,這個(gè)是官方明確說(shuō)的。我們還應(yīng)該清楚,其中的緣由。
參數(shù)是基本數(shù)據(jù)類型,復(fù)制的是具體值;如果參數(shù)是引用類型,把地址當(dāng)成值,復(fù)制的是地址;還有String類是一個(gè)非常特殊的類,她是不可變的。
到此這篇關(guān)于一文了解為什么Java中只有值傳遞的文章就介紹到這了,更多相關(guān)Java值傳遞內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
從零實(shí)現(xiàn)一個(gè)簡(jiǎn)單的Spring Bean容器的代碼案例
Spring是一個(gè)非常流行的Java?Web開(kāi)發(fā)框架,它提供了強(qiáng)大的依賴注入、面向切面編程、聲明式事務(wù)管理等功能,為開(kāi)發(fā)者提供了高效、快速地構(gòu)建Web應(yīng)用程序的工具,在這篇文章中,咱們將一步一步地構(gòu)建一個(gè)簡(jiǎn)單的SpringBean容器,需要的朋友可以參考下2023-06-06
Java畢業(yè)設(shè)計(jì)之多用戶宿舍管理系統(tǒng)的實(shí)現(xiàn)
這篇文章主要介紹了基于Java實(shí)現(xiàn)的多用戶宿舍管理系統(tǒng),本文采用了jsp、servlet、jdbc等技術(shù),文中示例代碼講解詳細(xì),需要的可以參考一下2022-02-02
Java?Stream流的常見(jiàn)生成和操作方法總結(jié)
從Java1.8開(kāi)始提出了Stream流的概念,本文將通過(guò)示例為大家詳細(xì)講解一下Stream流的常見(jiàn)生成和操作方法,感興趣的小伙伴可以了解一下2022-09-09
Java中對(duì)null進(jìn)行強(qiáng)制類型轉(zhuǎn)換的方法
小編對(duì)null進(jìn)行強(qiáng)轉(zhuǎn)會(huì)不會(huì)拋錯(cuò),非常的好奇,下面小編通過(guò)實(shí)例代碼給大家介紹Java中對(duì)null進(jìn)行強(qiáng)制類型轉(zhuǎn)換的方法,感興趣的朋友參考下吧2018-09-09
用SpringBoot Admin監(jiān)控SpringBoot程序
這篇文章主要介紹了用SpringBoot Admin監(jiān)控SpringBoot程序,幫助大家更好的理解和使用springboot框架,感興趣的朋友可以了解下2020-10-10
Java Spring Boot實(shí)現(xiàn)簡(jiǎn)易掃碼登錄詳解
這篇文章主要為大家詳細(xì)介紹了java Spring Boot實(shí)現(xiàn)app掃碼登錄功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助2021-09-09
Sublime Text 打開(kāi)Java文檔中文亂碼的解決方案
這篇文章主要介紹了Sublime Text 中文亂碼的解決方案,幫助大家更好的理解和使用Java,感興趣的朋友可以了解下2020-12-12

