作一個積極的人java
編碼、改bug、提高本身編程
我有一個樂園,面向編程,春暖花開!設計模式
推薦閱讀數組
第一季
0、Java的線程安全、單例模式、JVM內存結構等知識梳理安全
二、Java內存管理-初始JVM和JVM啓動流程(二)多線程
三、Java內存管理-JVM內存模型以及JDK7和JDK8內存模型對比總結(三)學習
四、Java內存管理-掌握虛擬機類加載機制(四)this
七、Java內存管理-掌握自定義類加載器的實現(七)
第一季總結:由淺入深JAVA內存管理 Core Story第二季
九、Java內存管理-」一文掌握虛擬機建立對象的祕密」(九)
十、Java內存管理-你真的理解Java中的數據類型嗎(十)
十一、Java內存管理-Stackoverflow問答-Java是傳值仍是傳引用?(十一)
十二、Java內存管理-探索Java中字符串String(十二)
實戰
分享一位老師的人工智能教程。零基礎!通俗易懂!風趣幽默!你們能夠看看是否對本身有幫助,點擊這裏查看【人工智能教程】。接下來進入正文。
勿在流沙築高臺,出來混早晚要還的。
本文導圖:
分享一位老師的人工智能教程。零基礎!通俗易懂!風趣幽默!你們能夠看看是否對本身有幫助,點擊這裏查看【人工智能教程】。接下來進入正文。
@[toc]
在Stack Overflow
看到這樣一個問題:
Is Java 「pass-by-reference」 or 「pass-by-value」?
翻譯成中文:
Java是傳值仍是傳引用?
請先不要看下面的內容,思考10秒後,在繼續閱讀!!!
爲何建議先思考,在閱讀內容呢?
咱們天天可能會利用碎片化的時間閱讀不少內容,有不少信息和知識其實在大腦過一下,而後就忘記了!如何才能高效的利用碎片化時間掌握或者記住更多的內容和知識,我本身碎片化閱讀的理解和技巧:閱讀一篇本身感興趣技術文章,在時間容許的時間下,必定是一次性閱讀完,在閱讀中帶着本身的問題,閱讀後有本身的簡單總結。 千萬不要閱讀 一段內容,看到微信有人發消息給你,就切換聊天框回覆消息,而後回覆完再切換回來閱讀技術文章。這種 大腦 的切換是須要耗費資源的,也影響閱讀的效果和效率(大腦在多個任務切換相似cpu多線程調度,線程的頻繁切換。就如多線程不必定能提供效率,頻繁的線程/任務切換耗費cpu大量資源)!
扯遠 了,切換回到本文正題,Java是傳值仍是傳引用?
我相信你閱讀完本篇後必定可以回答上面的問題,而且在工做在寫相似傳參的代碼也會有更深刻的理解。開啓探索之旅,Let's go!
在Java程序中會包含方法,方法會分爲方法聲明和方法實現,在方法聲明中又有參數列表,參數根據調用後的效果不一樣,也就是是否改變參數的原始值,能夠劃分爲兩種: 按值傳遞參數和按引用傳遞參數。
也就是以前介紹過的Java的基本類型和引用類型,若是方法參數中傳遞的基本類型就認爲是 按值傳遞(傳值),方法參數中傳遞的是引用類型,就稱之爲按引用傳遞(傳引用)。
一段簡單的代碼:
public class PrettyGirl {
/**
* 芳齡幾何
*/
int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public static void main(String[] args) {
// 引用類型
PrettyGirl prettyGirl = new PrettyGirl();
prettyGirl.setAge(28);
// 基本類型
int num = 50;
// 數組arrs也引用類型
int[] arrs = new int[]{2,0,1,9};
System.out.println("mian 中 num = " + num);
System.out.println("mian 中 arrs[3] = " + arrs[3]);
System.out.println("mian 中 prettyGirl.getAge() = " + prettyGirl.getAge());
System.out.println("-----------------------------------------");
// 調用 change方法
prettyGirl.change(num, arrs, prettyGirl);
System.out.println("調用change 後 mian 中 num = " + num);
System.out.println("調用change 後 mian 中 arrs[3] = " + arrs[3]);
System.out.println("調用change 後 mian 中 prettyGirl.getAge() = " + prettyGirl.getAge());
}
public void change(int pnum, int[] parrs, PrettyGirl ppg) {
//在change中 改變值類型pnum的值
pnum = pnum + 50;
//在change中 改變引用類型 parrs,ppg 的值
parrs[3] = 8;
// 從28變18
ppg.setAge(18);
System.out.println("change 中 pnum = " + pnum);
System.out.println("change 中 parrs[3] = " + parrs[3]);
System.out.println("change 中 ppg.getAge() = " + ppg.getAge());
System.out.println("-----------------------------------------");
}
}複製代碼
思考一下,打印的結果是什麼?
打印結果以下:
mian 中 num = 50
mian 中 arrs[3] = 9
mian 中 prettyGirl.getAge() = 28
-----------------------------------------
change 中 pnum = 100
change 中 parrs[3] = 8
change 中 ppg.getAge() = 18
-----------------------------------------
調用change 後 mian 中 num = 50
調用change 後 mian 中 arrs[3] = 8
調用change 後 mian 中 prettyGirl.getAge() = 18複製代碼
下面開啓分析之旅,結合以前學過的Java內存模型來畫上面代碼執行的內存變化的圖
注:下圖只是爲了演示講解說明,真實內存地址不必定是這樣!
int 類型變量num在棧中分配一塊內存,而 parrs 與 ppg 分配兩塊內存,棧中一塊,堆中一塊。當調用change方法時,建立三個變量 pnum,parrs,ppg這裏至關於把棧中的數據全備份一份給這三個數值,則有
在change方法中對傳遞的參數進行修改,此時pnum的值修改成 100,堆中ppg指向的對象年齡由28改成18,數組中parrs[3]修改成8。也就是 ppg與 parrs 改變了堆中的具體數值,而 pnum 改變的只是棧中的數值。
最後,當change方法調用結束,change棧幀被彈出,則對應的pnum,ppg,parrs 三個變量也消亡,此時只有main棧幀狀況以下圖:
經過上圖的演示,上面代碼的打印結果就很清晰明瞭了。
tips:回顧 java 棧
Java棧中存放的是一個個的棧幀,每一個棧幀對應一個被調用的方法,在棧幀中包括局部變量表(Local Variables)、操做數棧(Operand Stack)、指向當前方法所屬的類的運行時常量池(運行時常量池的概念在方法區部分會談到)的引用(Reference to runtime constant pool)、方法返回地址(Return Address)和一些額外的附加信息。當線程執行一個方法時,就會隨之建立一個對應的棧幀,並將創建的棧幀壓棧。當方法執行完畢以後,便會將棧幀出棧。所以可知,線程當前執行的方法所對應的棧幀一定位於Java棧的頂部。
根據上面例子中這樣的內存變換,想必你應該知道按值傳遞與按引用傳遞的深層緣由了吧!
從上圖中看全部的參數傳遞 本質都是按址值傳遞, 也就是內存地址的值 。 基本類型由於棧內存地址中保存就是其自己值,全部在參數傳遞的時候,拷貝自己的值進行傳遞,而引用類型在棧內存地址中保存的是引用的值,經過棧內存保存引用的值指向堆中獲取對象真是的值,在參數傳遞的時候,拷貝的是引用的值。
全部在方法傳遞參數後,若是基本類型的值在傳遞的方法中有修改,不會影響傳遞前方法中的值。而引用類型就不一樣了,由於它修改的是引用地址指向堆中數據,這部分數據在參數傳遞的時候不會拷貝一份,就如上面圖解標識出的同樣。
在Java中,對象經過引用傳遞,基本類型按值傳遞。
這句話的描述有一半是不許確的。就如上面咱們圖中看到的那樣基本類型是按照值傳遞的; 引用類型是拷貝引用的址值傳遞的,也即對象不經過引用傳遞。正確的描述語句是對象引用也是按值傳遞。
其實在Java語言規範(JLS)中描述:Java 嚴格按值傳遞,能夠理解與C徹底相同,也就是Java中參數傳遞的本質是按址值傳遞。
若是你在閱讀完本篇後,對上面問題有本身的深刻的理解,有歡迎文末留言一塊兒探討!
備註: 因爲本人能力有限,文中如有錯誤之處,歡迎指正。
Is Java 「pass-by-reference」 or 「pass-by-value」?
Java is Pass-by-Value, Dammit!
謝謝你的閱讀,若是您以爲這篇博文對你有幫助,請點贊或者喜歡,讓更多的人看到!祝你天天開心愉快!