亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

學習心得:Java基本功之Reference詳解

2019-11-18 13:07:43
字體:
來源:轉載
供稿:網友

  有這樣一種說法,如今爭鋒于IT戰場的兩大勢力,MS一族偏重于底層實現,java一族偏重于系統架構。說法根據無從考證,但從兩大勢力各自的社區力量和圖書市場已有佳作不難看出,此說法不虛。于是,事情的另一面讓人忽略了。偏巧,我是一個喜歡探究底層實現的Java程序員,雖然我的喜好并非純正咖啡,劍走偏鋒卻別是一番風味。
  
  Reference Java世界泰山北斗級大作《Thinking In Java》切入Java就提出“Everything is Object”。在Java這個布滿Object的世界中,reference是一切謎題的根源,所有的故事都是從這里開始的。
  
  Reference是什么?
  
  假如你和我一樣在進入Java世界之前曾經浪跡于C/C++世界,就一定不會對指針生疏。談到指針,往日種種不堪回首的經歷一下子涌上心頭,這里不是抱怨的地方,讓我們暫時忘記指針的痛苦,回憶一下最初接觸指針的甜蜜吧!
  
  還記得你看過的教科書中,如何講解指針嗎?留在我印象中的一種說法是,指針就是地址,如同門牌號碼一樣,有了地址,你可以輕而易舉找到一個人家,而不必費盡心力的大海撈針。C++登上歷史舞臺,reference也隨之而來,容我問個小問題,指針和reference區別何在?我的答案來自于在C++世界享譽盛名的《More Effective C++》。
  
  沒有null reference,reference必須有初值。
  
  使用reference要比使用指針效率高。因為reference不需要測試其有效性。指針可以重新賦值,而reference總是指向它最初獲得的對象。
  
  設計選擇:
  
  當你指向你需要指向的某個東西,而且絕不會改指向其它東西,或是當你實作一個運算符而其語法需要無法有指針達成,你就應該選擇reference。其它任何時候,請采用指針。
  
  這和Java有什么關系?
  
  初學Java,鑒于reference的名稱,我毫不猶豫的將它和C++中的reference等同起來。不過,我錯了。在Java中,reference 可以隨心所欲的賦值置空,對比一下上面列出的差異,就不難發現,Java的reference假如要與C/C++對應,它不過是一個穿著 reference外衣的指針而已。于是,所有關于C中關于指針的理解方式,可以照搬到Java中,簡而言之,reference就是一個地址。我們可以把它想象成一個把手,抓住它,就抓住了我們想要操縱的數據。如同把握C的要害在于把握指針,探索Java的鑰匙就是reference。
  
  一段小程序
  
  我知道,太多的文字總是令人犯困,那就來段代碼吧!
  
  public class ReferenceTricks
  {
  public static void main(String[] args)
  {
  ReferenceTricks r = new ReferenceTricks();
  // reset integer
  r.i = 0;
  System.out.PRintln
  ("Before changeInteger:" + r.i);
  changeInteger(r);
  System.out.println
  ("After changeInteger:" + r.i);
  
  // just for format
  System.out.println();
  
  // reset integer
  r.i = 0;
  System.out.println
  ("Before changeReference:" + r.i);
  changeReference(r);
  System.out.println
  ("After changeReference:" + r.i);
  }
  
  private static void
  changeReference(ReferenceTricks r)
  {
  r = new ReferenceTricks();
  r.i = 5;
  System.out.println
  ("In changeReference: " + r.i);
  }
  
  private static void
  changeInteger(ReferenceTricks r)
  {
  r.i = 5;
  System.out.println
  ("In changeInteger:" + r.i);
  }
  
  public int i;
  }
  
  我知道,把一個字段設成public是一種不好的編碼習慣,這里只是為了說明問題。假如你有愛好自己運行一下這個程序。你已經運行過了嗎?結果如何?是否如你預期?下面是我在自己的機器上運行的結果:
  
  Before changeInteger:0
  In changeInteger:5
  After changeInteger:5
  
  Before changeReference:0
  In changeReference: 5
  After changeReference:0
  
  這里,我們關注的是兩個change,changeReference和changeInteger。從輸出的內容中,我們可以看出,兩個方法在調用前和調用中完全一樣,差異出現在調用后的結果。
  
  糊涂的講解
  
  先讓我們來分析一下changeInteger的行為。
  
  前面說過了,Java中的reference就是一個地址,它指向了一個內存空間,這個空間存放著一個對象的相關信息。這里我們暫時不去關心這個內存具體如何排布,只要知道,通過地址,我們可以找到r這個對象的i字段,然后我們給它賦成5。
  
  既然這個字段的內容得到了修改,從函數中返回之后,它自然就是改動后的結果了,所以調用之后,r對象的i字段依然是5。下圖展示了changeInteger調用前后內存變化。
  
  讓我們把目光轉向changeReference。從代碼上,我們可以看出,同changeInteger之間的差別僅僅在于多了這么一句:
  
  r = new ReferenceTricks();
  
  這條語句的作用是分配一塊新的內存,然后將r指向它。執行完這條語句,r就不再是原來的r,但它依然是一個ReferenceTricks的對象,所以我們依然可以對這個r的i字段賦值。到此為止,一切都是那么自然。
  
  順著這個思路繼續下去的話,執行完changeReference,輸出的r的i字段,那么應該是應該是新內存中的i,所以應該是5。至于那塊被我們拋棄的內存,Java的GC功能自然會替我們善后的。
  
  事與愿違。
  
  實際的結果我們已經看到了,輸出的是0。肯定哪個地方錯了,究竟是哪個地方呢?
  
  參數傳遞的秘密
  
  知道方法參數如何傳遞嗎?
  
  記得剛開始學編程那會兒,老師教導,所謂參數,有形式參數和實際參數之分,參數列表中寫的那些東西都叫形式參數,在實際調用的時候,它們會被實際參數所替代。
  
  編譯程序不可能知道每次調用的實際參數都是什么,于是寫編譯器的高手就出個辦法,讓實際參數按照一定順序放到一個大家都可以找得到的地方,以此作為方法調用的一種約定。所謂“沒有規矩,不成方圓”,有了這個規矩,大家協作起來就輕易多了。這個公共數據區,現在編譯器的選擇通常是“棧”,而所謂的順序就是形式參數聲明的順序。
  
  顯然,程序運行的過程中,作為實際參數的變量可能遍布于內存的各個位置,而并不一定要老老實實的呆在棧里。為了守“規矩”,程序只好將變量復制一份到棧中,也就是通常所說的將參數壓入棧中。
  
  我剛才說什么來著?將變量復制一份到棧中,沒錯,“復制”!
  
  這就是所謂的值傳遞。
  
  C語言的曠世經典《The C Programming Language》開篇的第一章中,談到實際參數時說,“在C中,所有函數的實際參數都是傳‘值’的”。
  
  馬上會有人站出來,“錯了,還有傳地址,比如以指針傳遞就是傳地址”。不錯,傳指針就是傳地址。在把指針視為地址的時候,是否考慮過這樣一個問題,它也是一個變量。前面的討論中說過了,參數傳遞必須要把參數壓入棧中,作為地址的指針也不例外。所以,必須把這個指針也復制一份。函數中對于指針操作實際上是對于這個指針副本的操作。
  
  Java的reference等于C的指針。所以,在Java的方法調用中,reference也要復制一份壓入堆棧。在方法中對reference的操作就是對這個reference副本的操作。
  
  謎底揭曉
  
  好,讓我們回到最初的問題上。在changeReference中對于reference的賦值實際上是對這個reference的副本進行賦值,而對于reference的本尊沒有產生絲毫的影響。
  
  回到調用點,本尊醒來,它并不知道自己睡去的這段時間內發生過什么,所以只好當作什么都沒發生過一般。就這樣,副本消失了,在方法中對它的修改也就煙消云散了。
  
  也許你會問出這樣的問題,“聽了你的解釋,我反而對changeInteger感到迷惑了,既然是對于副本的操作,為什么changeInteger可以運作正常?”這是很有趣的現象。
  
  好,那我就用前面的說法解釋一下changeInteger的運作。所謂復制,其結果必然是副本完全等同于本尊。reference復制的結果必然是兩個reference指向同一塊內存空間。
  
  雖然在方法中對于副本的操作并不會影響到本尊,但對內存空間的修改確實實實在在的,回到調用點,雖然本尊依然不知道曾經發生過的一切,但它按照原來的方式訪問內存的時候,取到的確是經過方法修改之后的內容。于是方法可以把自己的影響擴展到方法之外。
  
  多說幾句
  
  這個問題起源于我對C/C++中同樣問題的思考。同C/C++相比,在changeReference中對reference賦值可能并不會造成什么很嚴重的后果,而在C/C++中,這么做卻會造成臭名昭著的“內存泄漏”,根本的原因在于Java擁有了可愛的GC功能。即便這樣,我仍不推薦使用這種的手法,究竟GC已經很忙了,我們怎么好意思再麻煩人家。
  
  在C/C++中,這個問題還可以繼續引申。既然在函數中對于指針直接賦值行不通,那么如何在函數中修改指針呢?答案很簡單,指針的指針,也就是把原來的指針看作一個普通的數據,把一個指向它的指針傳到函數中就可以了。
  
  同樣的問題到了Java中就沒有那么美妙的解決方案了,因為Java中可沒有reference的reference這樣的語法。可能的變通就是將reference進行封裝成類。至于值不值,公道安閑人心。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
久久午夜a级毛片| 97涩涩爰在线观看亚洲| 精品美女久久久久久免费| 日韩一级裸体免费视频| 欧美贵妇videos办公室| 91国产中文字幕| 欧美激情伊人电影| 国内精品视频久久| 国产精品视频xxxx| 亚洲精品中文字幕有码专区| 国产视频在线观看一区二区| 欧美性jizz18性欧美| 91久久精品国产91久久| 久久影视电视剧凤归四时歌| 日韩欧美一区二区三区久久| 夜夜狂射影院欧美极品| 成人精品一区二区三区电影免费| 欧美午夜丰满在线18影院| 亚洲人a成www在线影院| 国产精品尤物福利片在线观看| 国产伦精品一区二区三区精品视频| 欧洲中文字幕国产精品| 亚洲成人网在线| 久久久久国色av免费观看性色| 韩剧1988在线观看免费完整版| 亚洲成人在线视频播放| 精品久久久999| 国产精品久久久久久久一区探花| 97avcom| 亚洲高清福利视频| 成人美女av在线直播| 91黑丝高跟在线| 国产在线一区二区三区| 久久中文字幕在线| 欧美在线视频一区| 97视频在线播放| 成人伊人精品色xxxx视频| 国产日韩在线亚洲字幕中文| 日韩的一区二区| 777国产偷窥盗摄精品视频| 久久久久久久国产精品视频| 亚洲欧美日韩中文视频| 亚洲第一免费网站| 成人淫片在线看| 久久久久久久久久国产| 欧美极品少妇xxxxⅹ免费视频| 日韩av最新在线| 国产成人黄色av| 久久视频国产精品免费视频在线| 亚洲午夜激情免费视频| 日韩人体视频一二区| 91久久精品美女高潮| 亚洲一区二区三区毛片| 日韩电影中文字幕av| 欧美巨大黑人极品精男| 久久久久中文字幕2018| 成人网在线视频| 成人免费观看49www在线观看| 精品香蕉一区二区三区| 欧美精品久久久久久久久| 国产精品中文久久久久久久| 黄色成人av在线| 精品一区二区三区四区| 成人网欧美在线视频| 美女扒开尿口让男人操亚洲视频网站| 97香蕉超级碰碰久久免费软件| 国产suv精品一区二区三区88区| 91亚洲人电影| 久久天天躁日日躁| 全色精品综合影院| 国产激情视频一区| 欧美大片大片在线播放| 日韩日本欧美亚洲| 日本成人免费在线| 92版电视剧仙鹤神针在线观看| 亚洲美女精品成人在线视频| 91精品在线看| 色樱桃影院亚洲精品影院| 视频一区视频二区国产精品| 亚洲丁香婷深爱综合| 欧美日韩久久久久| 亚洲女人天堂色在线7777| 国产亚洲精品一区二555| 51午夜精品视频| 久久全国免费视频| 国产欧亚日韩视频| 久久久久久免费精品| 岛国av一区二区在线在线观看| 亚洲黄页视频免费观看| 久久99精品久久久久久噜噜| 欧美一级片在线播放| 亚洲精品黄网在线观看| 色婷婷综合成人| 国产一区玩具在线观看| 欧美性猛交xxxx免费看漫画| 亚洲人成毛片在线播放| 91免费版网站入口| 日韩av免费看| 91黑丝在线观看| 欧洲美女免费图片一区| 色综合久久久888| 亚洲最大av在线| 51精品国产黑色丝袜高跟鞋| 91免费的视频在线播放| 久热国产精品视频| 69久久夜色精品国产69| 91久久在线播放| 成人精品一区二区三区| 亚洲欧洲自拍偷拍| 国产日韩欧美夫妻视频在线观看| 国产美女久久精品香蕉69| 亚洲奶大毛多的老太婆| 国产精品狼人色视频一区| 欧美丰满少妇xxxx| 97av在线视频免费播放| 久久精品国产清自在天天线| 午夜精品一区二区三区在线| 日韩在线观看免费全| 国产精品第七影院| 成人午夜一级二级三级| 亚洲精品欧美一区二区三区| 欧美性猛交xxxx免费看| 久久免费精品日本久久中文字幕| 日韩69视频在线观看| 成人激情视频在线播放| 亚洲精品成人久久| 国产国语刺激对白av不卡| 高清欧美性猛交xxxx黑人猛交| 国产精品一区电影| y97精品国产97久久久久久| 欧美国产激情18| 色婷婷综合久久久久中文字幕1| 国产精品入口夜色视频大尺度| www欧美xxxx| 伊人久久五月天| 国产做受69高潮| 免费99精品国产自在在线| 中文字幕日韩精品在线观看| 国产91亚洲精品| 国产视频在线观看一区二区| 亚洲精品国产suv| 国产91热爆ts人妖在线| 亚洲a中文字幕| 2018国产精品视频| 久久香蕉国产线看观看网| 国产97在线观看| 韩国三级日本三级少妇99| 成人国产精品色哟哟| 日韩精品极品在线观看| 日韩精品免费观看| 欧美国产亚洲视频| 日韩av在线网| 国内精品小视频| 色老头一区二区三区| 亚洲裸体xxxx| 日韩高清a**址| 久久国产精品视频| 自拍偷拍免费精品| 成人精品福利视频| 国产精品一久久香蕉国产线看观看| 亚洲午夜未满十八勿入免费观看全集| 色综合久久悠悠| 欧美性猛xxx| 亚洲精品自拍第一页|