带你深入理解值传递(点进来才知道它是一篇使你收益的文章)
猜你想看:
序列化和反序列化為什么要實現Serializable接口?:https://blog.csdn.net/Kevinnsm/article/details/115356975?spm=1001.2014.3001.5501
“==“和equals的區別是什么(史上最全總結、最靠譜):https://blog.csdn.net/Kevinnsm/article/details/115427761?spm=1001.2014.3001.5501
最近翻看了很多關于值傳遞的文章,發現好多不同的見解,這果然是一個魚龍混雜的時代,沒錯我就是那條咸魚。
哈😀,進入今天的正題,帶你從底層認識值傳遞。【CSDN商業化--------》希望官方不要限流,縱然我沒充過會員】
如果你擁有以下幾個疑問,那么希望你花費你分鐘看完這篇文章。讓這篇文章凸顯出它的價值。
| 你是否還不了解值傳遞? |
| 你是否還認為Java也有引用傳遞? |
| 你是否認為基本類型就是值傳遞,引用類型就是引用傳遞? |
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Java只有值傳遞
為什么呢?先灌輸一下八股文
其實無論傳遞的參數是基本類型還是引用類型,都會在棧中創建一個副本。不同的是對于基本類型直接拷貝的是原始值(因為該變量在棧中存儲);對于引用類型來說,棧中存儲的是對象的引用(對象的地址),而真實的對象在堆中(對象在堆中被創建),此時你拷貝一份引用(地址),那么它還是指向堆中對象(地址不變嘛)
所以說,都是對副本進行操作;如果你不理解上面這一段,請看完下面的代碼分析
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
首先了解一下實參和形參
實參:在調用時傳遞給函數的參數
形參:定義函數名和函數體時使用的參數
例如
public class ValueTest {public static void main(String[] args) {int a = 10;test(a); //實際參數a}public static void test(int s) { //形式參數ss = 20;} }簡單了說就是:實參–>傳入;形參–>接收
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
然后看下面的代碼,當傳遞的是基本類型時
public class ValueTest {public static void main(String[] args) {int a = 10;System.out.printf("調用方法前a的值為%d",a);test(a);System.out.println();System.out.printf("調用方法后a的值為%d",a);}public static void test(int s) {s = 20;} }為什么會出現這個結果呢?很多人肯定都知道,變量的拷貝嘛。看下面的圖形分析
執行流程:
1.main方法入棧,棧中初始化了一個變量a=10
2.調用了test方法,棧中拷貝了一個副本變量a=10
3.修改副本變量對原始變量a沒有任何影響
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
當傳遞的是引用時
public class ValueTest {public static void main(String[] args) {User user = new User();user.setUsername("zsh");user.setPassword("zsh");System.out.printf("修改之前User的數據為%s\n",user);test(user);System.out.printf("修改之后User的數據為%s",user);}public static void test(User temp) {temp.setUsername("ad");temp.setPassword("ad");} }這是因為什么呢?且看下面的分析
當傳遞的是引用類型時,也會在棧中對其進行拷貝,只不過此時拷貝的是地址,由于副本和原始的地址相同,所以兩者都指向堆中的User對象;一旦對副本的引用進行操作(0x98.username=ad,0x98.password=ad),則相當于修改了堆中對象的數據
看下面的debug模式下的分析
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
當我傳遞的是String類型時,會出現什么情況呢?
當我瀏覽網上關于傳遞的是String類型時,發現很多人講的是真的離譜,完全沒有看到重點,明明一個final可以解決的,非要扯一堆東東。
public class ValueTest {public static void main(String[] args) {String str = "zsh";System.out.printf("調用方法前str為:%s\n",str);test(str);System.out.printf("調用方法后str為:%s",str);}public static void test(String temp) {temp = "Ronin";} }
是不是感到匪夷所思,我們都知道String也是對象,那為什么調用前后的數據相同呢?
其實這要追溯到String的底層源碼
public final class String從這個final關鍵字你就明白了,因為String是不可變的;所以當你修改時,其實是相當于重新new了一個對象,容我細細道來。
流程分析
1.首先調用函數,傳遞拷貝的地址副本,我們都知道和上面傳遞的User引用一樣
2.然后當執行到temp = "Ronin"時,由于String類型的不可變性,所以會重新創建一個String對象,將temp指向新的String對象(將地址賦給temp)。
最后結果如下
debug下分析地址變化
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
下面測試一下你理解值傳遞沒
public class ValueTest {public static void main(String[] args) {User user = new User();user.setUsername("zsh");user.setPassword("zsh");System.out.printf("before:%s\n",user);test(user);System.out.printf("after:%s\n",user);}public static void test(User temp) {temp = new User();temp.setUsername("af");temp.setPassword("af");} }結果:
before:User{username=‘zsh’, password=‘zsh’}
after:User{username=‘zsh’, password=‘zsh’}
這個就不用多說了吧,temp = new User();創建一個User對象后,將地址賦給temp,然后main中的引用和test中的引用就完全是兩碼事了
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
本文章到這里馬上就該結束了。好傷心😢😢
總結
總的來說無論傳遞的是基本類型還是引用類型,本質上都是值傳遞;只不過基本類型是對變量值的拷貝,引用類型是對地址值的拷貝(地址值也是值)。
總結
以上是生活随笔為你收集整理的带你深入理解值传递(点进来才知道它是一篇使你收益的文章)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 你是否真正理解了泛型、通配符、类型擦除
- 下一篇: “==“和equals的区别是什么(史上