一文了解為什么Java中只有值傳遞
經(jīng)典的問題
Java 傳參是值傳遞還是引用傳遞?這個問題很基礎(chǔ),但是許多人都有點懵
形參&實參
首先我們得了解關(guān)于參數(shù)的幾個概念
形式參數(shù):定義函數(shù)時使用的參數(shù),用來接收函數(shù)傳入?yún)?shù),比如我們寫個函數(shù),函數(shù)中的參數(shù)為形式參數(shù)
public void test(String str) { //str為形式參數(shù) System.out.println(str); }
實際參數(shù):我們調(diào)用函數(shù)時,函數(shù)名后面括號中的參數(shù)稱為實際參數(shù),必須有確定的值,如下面例子所示
public static void main(String[] args) { A a = new A(); a.test("小 明"); //"小 明"則為實際參數(shù) }
可以發(fā)現(xiàn),當(dāng)調(diào)用一個有參函數(shù)的時候,會把實際參數(shù)傳遞給形式參數(shù)。
這種傳遞的過程的參數(shù)一般有2種情況值傳遞和引用傳遞。
- 值傳遞:調(diào)用函數(shù)時將實際參數(shù)復(fù)制一份傳遞到函數(shù)中,函數(shù)內(nèi)部對參數(shù)內(nèi)部進(jìn)行修改不會影響到實際參數(shù),即創(chuàng)建副本,不會影響原生對象
- 引用傳遞 :方法接收的是實際參數(shù)所引用的地址,不會創(chuàng)建副本,對形參的修改將影響到實參,即不創(chuàng)建副本,會影響原生對象
我們還得知道:在Java中有2種數(shù)據(jù)類型,其中主要有基本數(shù)據(jù)類型和引用數(shù)據(jù)類型,除了8種基本數(shù)據(jù)類型以外都是引用數(shù)據(jù)類型,分別是byte,short,int,long,char,boolean,float,double
Java是值傳遞還是引用傳遞
對于這個問題,我們先來看幾個例子慢慢道來:
傳參的類型:基本數(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)對變量重新賦值,并未改變變量num1和num2的值,改變的只是change()方法內(nèi)的num1和num2的副本。我們需要知道,基本數(shù)據(jù)類型在內(nèi)存中只有一塊存儲空間,分配在棧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)メ烎~"); System.out.println("after change...."); System.out.println("param1 = " + param1); System.out.println("param2 = " + param2); } }
結(jié)果:
param1 = 小明
param2 = 今天天氣好
after change....
param1 = 小張
param2 = 今天天氣好,我們?nèi)メ烎~
str = 小明
str2 = 今天天氣好,我們?nèi)メ烎~
我們發(fā)現(xiàn)str變量沒有改變,但是str2變量卻改變了,大家是不是迷惑了:Java傳參的類型如果是引用數(shù)據(jù)類型,是值傳遞還是引用傳遞?
其實大家被一堆術(shù)語給忽悠了,筆者畫了2張圖,幫助大家理解:
before change():
after change():
在Java中,除了基本數(shù)據(jù)類型以外,其他的都是引用類型,引用類型在內(nèi)存中有兩塊存儲空間(一塊在棧stack中,一塊在堆heap中)。
如果參數(shù)是引用類型,傳遞的就是實參所引用的對象在棧中地址值的拷貝,這里創(chuàng)建的副本是 地址的拷貝。那就有人說了,可是它值變了呀,這明明就是"引用傳遞"嘛?
我們可以換個角度理解,如果我們把棧地址當(dāng)成值,會創(chuàng)建棧地址副本(復(fù)制棧幀),棧地址最終并沒有改變,改變的是堆內(nèi)存中的值。這就好比棧地址是鑰匙,我們copy了一把,它能打開保險箱。我們關(guān)心的是鑰匙有沒有花紋這種變化,至于打開保險箱后的錢多錢少,我們并不需要關(guān)心。
雖然調(diào)用完函數(shù)后,str2變量值(堆中的數(shù)據(jù))改變了,但是參數(shù)是引用類型,傳遞的實參是 棧中地址值,這是我們關(guān)心的,拷貝的是棧中地址值,最終棧中地址值并沒有改變。所以是符合值傳遞的定義創(chuàng)建副本,不會影響原生對象。
可能又有人問了,那str變量值為啥沒有改變呢?其實這完全是由于String類
的特殊,我們知道它是不可變的final,這個時候在函數(shù)中 param1= "小張";其實會隱式創(chuàng)建一個新的String對象,同時堆內(nèi)存中會開辟一個新的內(nèi)存空間,param1指向了這個新開辟的內(nèi)存空間。原地址str指向的堆內(nèi)存空間中數(shù)據(jù)沒有任何改變。
尾語
Java中只有值傳遞,始終是傳值的,我們要牢記,這個是官方明確說的。我們還應(yīng)該清楚,其中的緣由。
參數(shù)是基本數(shù)據(jù)類型,復(fù)制的是具體值;如果參數(shù)是引用類型,把地址當(dāng)成值,復(fù)制的是地址;還有String類是一個非常特殊的類,她是不可變的。
到此這篇關(guān)于一文了解為什么Java中只有值傳遞的文章就介紹到這了,更多相關(guān)Java值傳遞內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java爬蟲實現(xiàn)Jsoup利用dom方法遍歷Document對象
本文主要介紹了Java爬蟲實現(xiàn)Jsoup利用dom方法遍歷Document對象,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-05-05關(guān)于spring中事務(wù)的傳播機(jī)制
這篇文章主要介紹了關(guān)于spring中事務(wù)的傳播機(jī)制,所謂事務(wù)傳播機(jī)制,也就是在事務(wù)在多個方法的調(diào)用中是如何傳遞的,是重新創(chuàng)建事務(wù)還是使用父方法的事務(wù),需要的朋友可以參考下2023-05-05Java利用FileUtils讀取數(shù)據(jù)和寫入數(shù)據(jù)到文件
這篇文章主要介紹了Java利用FileUtils讀取數(shù)據(jù)和寫入數(shù)據(jù)到文件,下面文章圍繞FileUtils的相關(guān)資料展開怎么讀取數(shù)據(jù)和寫入數(shù)據(jù)到文件的內(nèi)容,具有一定的參考價值,徐婭奧德小伙伴可以參考一下2021-12-12Spring核心容器之ApplicationContext上下文啟動準(zhǔn)備詳解
這篇文章主要介紹了Spring核心容器之ApplicationContext上下文啟動準(zhǔn)備詳解,ApplicationContext 繼承自 BeanFactory ,其不僅包含 BeanFactory 所有功能,還擴(kuò)展了容器功能,需要的朋友可以參考下2023-11-11Java代碼為例講解堆的性質(zhì)和基本操作以及排序方法
堆數(shù)據(jù)結(jié)構(gòu)可以看作一顆完全二叉樹,因而又被成為二叉堆,這里我們以Java代碼為例講解堆的性質(zhì)和基本操作以及排序方法,需要的朋友可以參考下2016-06-06詳解SpringBoot基礎(chǔ)之banner玩法解析
SpringBoot項目啟動時會在控制臺打印一個默認(rèn)的啟動圖案,這個圖案就是我們要講的banner,這篇文章主要介紹了SpringBoot基礎(chǔ)之banner玩法解析,感興趣的小伙伴們可以參考一下2019-04-04MyBatis?Generator快速生成實體類和映射文件的方法
這篇文章主要介紹了MyBatis?Generator快速生成實體類和映射文件的方法,通過示例代碼介紹了MyBatis?Generator?的使用,本文結(jié)合示例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2023-10-10Java基礎(chǔ)之打印萬年歷的簡單實現(xiàn)(案例)
下面小編就為大家?guī)硪黄狫ava基礎(chǔ)之打印萬年歷的簡單實現(xiàn)(案例)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-07-07