Java必踩的坑之方法中形參、實(shí)參傳遞
首先亮明Java中方法參數(shù)傳遞的規(guī)則,這兩點(diǎn)很重要:
- 如果實(shí)參是基本類型(包括包裝類型)或者String,則實(shí)參不會(huì)變(傳的是值);
- 如果實(shí)參是對(duì)象集合或者數(shù)組,則實(shí)參會(huì)改變(傳的是引用)。
上面這兩條比較簡(jiǎn)單,筆者就不展開說了,這里只說一點(diǎn),關(guān)于方法中引用的傳遞,很多人會(huì)踩坑,如下:
我們先以數(shù)組舉例,如下代碼,很簡(jiǎn)單的幾行,大家猜一下會(huì)最終輸出的結(jié)果是什么樣子的呢?
public class PassByValueDemo {
public static void main(String[] args) {
int[] i = {0};
new PassByValueDemo().Demo(i);
// 這個(gè)地方還是0
System.out.printf(Arrays.toString(i));
}
public void Demo(int[] i){
// 這個(gè)實(shí)參為數(shù)組,傳的是引用,其值會(huì)改變??? nonono,只是在這個(gè)方法中改變了,回到main方法棧中還是{0}。
i = new int[]{1,2,3};
System.out.println(Arrays.toString(i));
}
}
根據(jù)第二條規(guī)則如果實(shí)參是對(duì)象集合或者數(shù)組,則實(shí)參會(huì)改變(傳的是引用),大家很容易想到,這個(gè)實(shí)參為數(shù)組,傳的是引用,其值會(huì)改變,那就大錯(cuò)特錯(cuò)了。這個(gè)只會(huì)在方法中短暫改變數(shù)組的值,回到main方法棧中還是{0}。
實(shí)際輸出如下:
[1, 2, 3]
[0]
Process finished with exit code 0
為什么會(huì)這樣呢?具體分析如下:
- 我們先看main方法中第一行操作int [] i ={0},這個(gè)操作會(huì)在內(nèi)存中開辟一個(gè)4字節(jié)大小的內(nèi)存空間,然后返回其該數(shù)組的首地址,我們假設(shè)該數(shù)組的首地址值為0x1111,那么此時(shí)i就指向了內(nèi)存中0x1111這么一個(gè)空間。內(nèi)存地址為0x1111的空間存儲(chǔ)了0;
- 繼續(xù)往下指看,調(diào)用Demo方法,此時(shí)會(huì)保存mian方法棧的狀態(tài),包括i在mian方法中指向的內(nèi)存空間,這里點(diǎn)很重要,很重要,重要,重要的事情說三遍。
- 在Demo方法中 new Int[] {1,2,3},這個(gè)操作會(huì)重新在內(nèi)存中開辟一個(gè)空間,然后返回該數(shù)組的首地址的值,我們把這個(gè)地址值假設(shè)為0x2222,內(nèi)存為0x2222存儲(chǔ)了1,2,3;此時(shí)i的值指向了0x2222;那么這個(gè)時(shí)候輸出i,當(dāng)然會(huì)打印1,2,3;
- 執(zhí)行完了Demo方法,我們回到main方法中,此時(shí)從虛擬機(jī)棧中恢復(fù)剛才進(jìn)入Demo方法前保存的棧信息,在進(jìn)入Demo方法前i是指向0x1111這么一個(gè)地址空間,進(jìn)入前已經(jīng)保存了棧中的局部變量表中(局部變量表可參考筆者該篇博文:點(diǎn)擊我),我們現(xiàn)在取出來,那么i的指向的就是0x1111,而不是0x2222,此時(shí)打印的是0x1111指向的值,也就是0;
雖然我們不能改變引用地址,但是可以改變引用指向的地址空間里的值,如下:
public class PassByValueDemo {
public static void main(String[] args) {
int[] i = {0};
new PassByValueDemo().Demo(i);
System.out.printf(Arrays.toString(i));
}
public void Demo(int[] i){
i[0] = 1;
System.out.println(Arrays.toString(i));
}
}
輸出結(jié)果:
[1]
[1]
Process finished with exit code 0
熟悉C或C++的同學(xué)可以類比int *const(允許更改存儲(chǔ)在地址中的值),而不是int const*(允許指針指向其他地址)。
Java 形參和實(shí)參的區(qū)別:
形參 :就是形式參數(shù),用于定義方法的時(shí)候使用的參數(shù),是用來接收調(diào)用者傳遞的參數(shù)的。 形參只有在方法被調(diào)用的時(shí)候,虛擬機(jī)才會(huì)分配內(nèi)存單元,在方法調(diào)用結(jié)束之后便會(huì)釋放所分配的內(nèi)存單元。 因此,形參只在方法內(nèi)部有效,所以針對(duì)引用對(duì)象的改動(dòng)也無法影響到方法外。
實(shí)參 :就是實(shí)際參數(shù),用于調(diào)用時(shí)傳遞給方法的參數(shù)。實(shí)參在傳遞給別的方法之前是要被預(yù)先賦值的。 在本例中 swap 方法 的numa, numb 就是形參,傳遞給 swap 方法的 a,b 就是實(shí)參
注意:在值傳遞調(diào)用過程中,只能把實(shí)參傳遞給形參,而不能把形參的值反向作用到實(shí)參上。在函數(shù)調(diào)用過程中,形參的值發(fā)生改變,而實(shí)參的值不會(huì)發(fā)生改變。而在引用傳遞調(diào)用的機(jī)制中,實(shí)際上是將實(shí)參引用的地址傳遞給了形參,所以任何發(fā)生在形參上的改變也會(huì)發(fā)生在實(shí)參變量上。
總結(jié)
到此這篇關(guān)于Java必踩坑之方法中形參、實(shí)參傳遞的文章就介紹到這了,更多相關(guān)Java形參、實(shí)參傳遞內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
spring aop底層原理及如何實(shí)現(xiàn)
這篇文章主要介紹了spring aop底層原理及如何實(shí)現(xiàn),幫助大家更好的理解和學(xué)習(xí)使用spring aop,感興趣的朋友可以了解下2021-04-04
Java中Integer.valueOf,parsetInt() String.valueOf的區(qū)別和結(jié)果代碼解析
本文通過代碼給大家講解了JAVA中Integer.valueOf, parsetInt() String.valueOf的區(qū)別和結(jié)果,需要的朋友可以參考下2018-05-05
Java Swing實(shí)現(xiàn)餐廳點(diǎn)餐系統(tǒng)源碼(收藏版)
這篇文章主要介紹了Java Swing實(shí)現(xiàn)餐廳點(diǎn)餐系統(tǒng)源碼,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-02-02
Mybatis的一級(jí)緩存和二級(jí)緩存原理分析與使用
mybatis-plus 是一個(gè) Mybatis 的增強(qiáng)工具,在 Mybatis 的基礎(chǔ)上只做增強(qiáng)不做改變,為簡(jiǎn)化開發(fā)、提高效率而生,這篇文章帶你了解Mybatis的一級(jí)和二級(jí)緩存2021-11-11
Java 字符串轉(zhuǎn)float運(yùn)算 float轉(zhuǎn)字符串的方法
今天小編就為大家分享一篇Java 字符串轉(zhuǎn)float運(yùn)算 float轉(zhuǎn)字符串的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-07-07
Spring攔截器HandlerInterceptor接口代碼解析
這篇文章主要介紹了Spring攔截器HandlerInterceptor接口代碼解析,具有一定借鑒價(jià)值,需要的朋友可以參考下2017-12-12
快速解決SpringMVC @RequestBody 用map接收請(qǐng)求參數(shù)的問題
今天小編就為大家分享快速解決SpringMVC @RequestBody 用map接收請(qǐng)求參數(shù)的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-08-08

