一文瞭解為什麼Java中隻有值傳遞
經典的問題
Java 傳參是值傳遞還是引用傳遞?這個問題很基礎,但是許多人都有點懵
形參&實參
首先我們得瞭解關於參數的幾個概念
形式參數:定義函數時使用的參數,用來接收函數傳入參數,比如我們寫個函數,函數中的參數為形式參數
public void test(String str) { //str為形式參數 System.out.println(str); }
實際參數:我們調用函數時,函數名後面括號中的參數稱為實際參數,必須有確定的值,如下面例子所示
public static void main(String[] args) { A a = new A(); a.test("小 明"); //"小 明"則為實際參數 }
可以發現,當調用一個有參函數的時候,會把實際參數傳遞給形式參數。
這種傳遞的過程的參數一般有2種情況值傳遞和引用傳遞。
- 值傳遞:調用函數時將實際參數復制一份傳遞到函數中,函數內部對參數內部進行修改不會影響到實際參數,即創建副本,不會影響原生對象
- 引用傳遞 :方法接收的是實際參數所引用的地址,不會創建副本,對形參的修改將影響到實參,即不創建副本,會影響原生對象
我們還得知道:在Java中有2種數據類型,其中主要有基本數據類型和引用數據類型,除瞭8種基本數據類型以外都是引用數據類型,分別是byte,short,int,long,char,boolean,float,double
Java是值傳遞還是引用傳遞
對於這個問題,我們先來看幾個例子慢慢道來:
傳參的類型:基本數據類型
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); } }
結果:
param1 = 10
param2 = 20
after change….
param1 = 333param2 = 444
==============
num1 = 10
num2 = 20
我們可以發現,change()方法內對變量重新賦值,並未改變變量num1和num2的值,改變的隻是change()方法內的num1和num2的副本。我們需要知道,基本數據類型在內存中隻有一塊存儲空間,分配在棧stack中。
Java傳參的類型如果是基本數據類型,是值傳遞。
傳參的類型:引用數據類型
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(",我們去釣魚"); System.out.println("after change...."); System.out.println("param1 = " + param1); System.out.println("param2 = " + param2); } }
結果:
param1 = 小明
param2 = 今天天氣好
after change….
param1 = 小張param2 = 今天天氣好,我們去釣魚
str = 小明
str2 = 今天天氣好,我們去釣魚
我們發現str變量沒有改變,但是str2變量卻改變瞭,大傢是不是迷惑瞭:Java傳參的類型如果是引用數據類型,是值傳遞還是引用傳遞?
其實大傢被一堆術語給忽悠瞭,筆者畫瞭2張圖,幫助大傢理解:
before change():
after change():
在Java中,除瞭基本數據類型以外,其他的都是引用類型,引用類型在內存中有兩塊存儲空間(一塊在棧stack中,一塊在堆heap中)。
如果參數是引用類型,傳遞的就是實參所引用的對象在棧中地址值的拷貝,這裡創建的副本是 地址的拷貝。那就有人說瞭,可是它值變瞭呀,這明明就是"引用傳遞"嘛?
我們可以換個角度理解,如果我們把棧地址當成值,會創建棧地址副本(復制棧幀),棧地址最終並沒有改變,改變的是堆內存中的值。這就好比棧地址是鑰匙,我們copy瞭一把,它能打開保險箱。我們關心的是鑰匙有沒有花紋這種變化,至於打開保險箱後的錢多錢少,我們並不需要關心。
雖然調用完函數後,str2變量值(堆中的數據)改變瞭,但是參數是引用類型,傳遞的實參是 棧中地址值,這是我們關心的,拷貝的是棧中地址值,最終棧中地址值並沒有改變。所以是符合值傳遞的定義創建副本,不會影響原生對象。
可能又有人問瞭,那str變量值為啥沒有改變呢?其實這完全是由於String類
的特殊,我們知道它是不可變的final,這個時候在函數中 param1= "小張";其實會隱式創建一個新的String對象,同時堆內存中會開辟一個新的內存空間,param1指向瞭這個新開辟的內存空間。原地址str指向的堆內存空間中數據沒有任何改變。
尾語
Java中隻有值傳遞,始終是傳值的,我們要牢記,這個是官方明確說的。我們還應該清楚,其中的緣由。
參數是基本數據類型,復制的是具體值;如果參數是引用類型,把地址當成值,復制的是地址;還有String類是一個非常特殊的類,她是不可變的。
到此這篇關於一文瞭解為什麼Java中隻有值傳遞的文章就介紹到這瞭,更多相關Java值傳遞內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!