stone2083

          effective java讀后感1(1-5點)

          effective java中提供了57條建議。針對這些建議,我談談自己的理解。

          1.考慮用靜態工廠方法代替構造函數
          靜態工廠方式相比于構造函數的兩個優點:
          1)可以有符合自己身份的方法名,方便客戶端代碼的閱讀
          2)調用的時候,不要求創建一個新的實例。可以返回緩存實例,或者singleton實例等

          靜態工廠方法的最大缺點:
          如果類中沒有public或者protected的構造函數,使用靜態工廠方法的方式得到實例,那么這個類就無法被繼承。
          比如
          public class Demo {
              
          private static Demo demo = new Demo();

              
          public static Demo getInstance() {
                  
          return demo;
              }

              
          private Demo() {
              }
          }
          那么這個類就無法被繼承。
          (當然,鼓勵使用組合,而不是繼承)

          在spring沒有流行起來的那些日子里,我大量使用工廠方法,但是使用spring等ioc容器后,這一切都是交給容器去處理了。或許,在客戶端代碼中,工廠模式會因為這些ioc的出>現,而遭受淘汰。


          2.使用私有構造函數強化singleton屬性

          一旦存在public或者protected的構造函數,那么無法保證一個類,一定是sinleton的。因為無法得知客戶端代碼是使用構造函數,還是同構靜態方法去得到類實例。所以對于一個嚴格要求singleton的類,那么其構造函數必須是私有的。
          既然說到singleton了,那么順便說下幾個常見的創建方法
          1)
          /**
           * 優點:簡單,而且可以確保一定是singletion實例
           * 缺點:類加載時,就會初始化實例,不能做到延遲初始化。
           
          */
          public class Demo {
              
          private static final Demo demo = new Demo();

              
          public static Demo getInstance() {
                  
          return demo;
              }

              
          private Demo() {
              }
          }
          2)
          /**
           * 優點:lazy load(延遲初始化實例),提高效率
           * 缺點:多線程情況下,可能初始化多份實例
           
          */
          public class Demo {
              
          private static Demo demo = null;

              
          public static Demo getInstance() {
                  
          if(demo  == null ) {
                      demo 
          = new Demo();
                  }
                  
          return demo;
              }

              
          private Demo() {
              }
          }
          3)
          /**
           * 優點:lazy load(延遲初始化實例),提高效率
           *              采用double check并且同步的方式,理論上確保在多線程的應用場景中,也只創建一份實例
           * 備注:(涉及到jvm的實現,在實際應用中,也可能生成多份實例,但是幾率是相當地低)
           
          */
          public class Demo {
              
          private static Demo demo = null;

              
          public static Demo getInstance() {
                  
          if(demo  == null ) {
                      
          synchronized(Demo.class)  {
                          
          if(demo == null) {
                              demo 
          = new Demo();
                          }
                      }
                  }
                  
          return demo;
              }

              
          private Demo() {
              }
          }


          3.使用私有構造函數強化不可實例化能力
          咋一看這個標題,覺得不可思議,居然讓類不具備實例化能力。但是確實也有一些應用場景,比如一些util類,就不需要實例化。但是有很大的副作用,就是類無法被繼承。所以換成我,就算是util類,我還是會保留其public的構造函數的。客戶端就算要實例化這些util,也無傷大雅。


          4.避免創建重復對象
          一般情況下,請重復使用同一個對象,而不是每次需要的時候創建一個功能上等價的新對象。這主要是為了性能上的考慮,何況在一般的應用場景下,確實沒有必要去重復創建對象。當然有時候為了OO設計考慮,也不特別排斥創建重復的小對象。
          需要明確的是,避免創建重復的對象,請不要產生一個誤區就是:創建對象的成本非常昂貴。事實上,創建小對象的開銷是非常小的,而且現在的jdk gc對于小對象的GC代價也是非常廉價(在之后的日子里,我會針對sun jdk gc,做一次介紹)。比如在做Swing開發的時候,會創建很多EventListener對象,比如在Spring Framework中,就創建很多匿名內隱類對象實現類似ruby等動態語言的Closure(閉包)。
          但是也不可否認的是,創建大對象,對大對象的GC 的開銷是比較大的。比如初始化一個對象的時候,需要加載10m的文件內容到內存;創建數據庫連接對象等等,在這些場景下,創建的開銷是相當昂貴了,一定要盡可能避免重復對象的創建(除非特殊需求)。
          對于這些大對象,一般采用singleton模式,cache,或者object pool等方式,避免重復的創建。至于采用具體什么方式,需要根據具體的應用場景來決定了。


          5.消除過期對象的引用
          為什么要這么做?其實只要理解“java內存泄露”這個概念就可以了。java中的內存泄漏不同于C++中的內存泄漏。C++是需要程序員手工管理內存的語言,創建一個對象,用完之后,需要手工刪除這個對象。而java不一樣,jdk gc替程序員做了這件事情,一旦對象失去了引用之后,jdk gc就會自動回收這個對象。
          為了避免java中的內存泄漏,只需要知道一點就可以:對于無用的對象,必須消除對這個對象的引用。
          怎么消除對象的引用呢?難道需要手工設置“object=null;”,那么一旦程序中到處充斥著這樣的代碼,將會是一件非常惡心的事情,嚴重影響程序的閱讀性。
          正確的做法是,每個定義的變量給予最緊湊的作用域,一旦對象結束生命周期,自然就消除了對其的引用。
          當然在必要的場合,也不反對采用清空對象引用的方法,但是不推薦。
          內存泄漏的癥狀不能在短時間內反應出來,往往是在程序運行一段時間,一天,一周,一個月,甚至一年,才逐漸顯現的,一個經驗豐富的程序員,也不能確保其代碼一定不存在內存泄漏的問題。檢查內存泄漏問題,往往需要借助工具,heap profile,比如jprofile等等。在linux下面,可以使用jps jstat jinfo jmap等命令去觀察。



          posted on 2008-02-19 23:11 stone2083 閱讀(683) 評論(0)  編輯  收藏 所屬分類: java

          主站蜘蛛池模板: 镇巴县| 达孜县| 余庆县| 绿春县| 贵州省| 亳州市| 永靖县| 武宁县| 金平| 含山县| 汉川市| 方山县| 光山县| 宁夏| 应用必备| 阳新县| 金塔县| 襄汾县| 家居| 太仆寺旗| 锡林浩特市| 双城市| 玉环县| 和田市| 绥江县| 长葛市| 广平县| 谷城县| 兰州市| 扬中市| 荥经县| 罗山县| 阿巴嘎旗| 昌邑市| 永登县| 夏津县| 永川市| 琼结县| 山阳县| 斗六市| 中宁县|