你好,我是miniluo,今天我和你聊聊代碼中遇到的java值傳遞的坑。java
前不久,有個小夥伴遇到一個bug「明明給對象屬性賦了值,可用的時候仍是null」,搞不定因此要我幫忙看看。起初看了一遍也沒發現問題,再看第二遍的時候,發現了端倪,原來當符合某個條件時,會把對象賦空對象,同時該對象又會傳遞到子方法,子方法new了新對象,給屬性賦了值。數組
下面是一個簡單的例子,很好的還原了bug產生的現象。學習
@Test public void testRef() throws Exception{ Student student = null; initStudent(student); System.out.println(student); } private void initStudent(Student student){ student = new Student(); student.setName("Jack.luo"); }
其實咱們都知道Java是值傳遞。code
下面咱們就來分析下java爲何是值傳遞而不是引用傳遞(不要被對象所迷惑)。對象
咱們都知道堆存放的是對象實例、全局變量、數組(另外專題再聊JVM)。分析下代碼,testRef方法(主方法)中student只是在內存棧區建立,堆中並沒有此引用的指向,而此時傳遞給initStudent方法(子方法)的是空指向,因此在子方法new了對象後纔會在堆分配空間(地址),因此兩個方法中的student前者指向空,後者指向對象所在堆地址。內存
舉個例子:咱們把Student比做瓶子,A同窗2分鐘前說他要一個瓶子(口小底大);2分鐘後他說他擁有了一個瓶子(口小底大脖子細--【沒錯,就是醒酒瓶】);是否是不同?it
那咱們要怎麼解決這個問題呢?能夠有如下2中方案:io
方案1,確保主方法傳遞到子方法的student是一個非空對象;如此一來也就是說子方法接收到的是一個被分配了堆空間的地址(值),當你在子方法修改了屬性後就會覆蓋主方法設置過的屬性。一般,我不建議採用這種方法,當你的業務代碼寫的不夠清晰,服務編排不合理就容易產生如文章開頭的坑。class
方案2,子方法直接返回對象,而不要用傳遞;如代碼所示:test
@Test public void testRef() throws Exception{ Student student = new Student(); student = initStudent(student); System.out.println(student); } private Student initStudent(Student student){ student.setName("Jack.luo"); return student; }
爲何java引用傳遞傳的也是對象的地址呢?其實,若每次傳遞都複製一份新值,遇到大對象則就會很佔內存空間且效率低,因此java採用的引用傳遞來解決這些問題。
思考和討論
剛剛的例子中咱們說的都是對象的引用傳遞,相信通過這個學習你已經掌握了java對象的傳遞其實本質仍是值傳遞,那你java中各類基本類型爲何能夠直接是值傳遞呢?歡迎留言與我分享和指正!也歡迎你把這篇文章分享給你的朋友或同事,一塊兒交流。
關注咱們的公衆號,不定時分享技術、管理、業務等不一樣領域的文章與您一塊兒學習交流。也歡迎投稿:xiaouoron@foxmail.com