題記:
花了一周把Peter Haggar的《practical Java》看了遍,有所感悟,年紀大了, 寫下筆記,友善日後檢視.也希望有緣之人可以看看,做個渺小的指路人。 不足之處還望指正。
全書分為六個部分,包括一般技術、對象與相等性、異常處理、性能、多線程、對象。
一般技術:舉例了幾個java常見錯誤用法的說明和解釋,諸如array和vector的選擇,多态與instanceof等等
對象和相等性則:針對equals的詳細說明,是迄今本人見過對equals了解最深的一本書了,其中不乏java的一些規範
異常處理:主要介紹了java異常機制的使用細節,其中有一點就是return後的邏輯一律不執行在try finally模式裡頭是無效的
性能:介紹了java常用的一些優化細節,諸如使用棧變量來代替堆變量,減少同步化,使用arraycopy方法來代替自己的循環複制數組等等
多線程:簡要的說明了java線程使用中一些常見的知識點,如果對java多線程有興趣的,可以看看《Java并發程式設計實戰》
對象:介紹了接口與繼承的關系與使用,對深入學習java架構源碼有一定的幫助,感興趣的可以多思考下其中的奧義
正題中将挑選自己覺得比較有用的一些知識點進行說明,但并不代表其他知識點就不重要(因人而異,盡信書 不如無書)
最後我會将代碼工程打包好,感興趣的可以去下載下傳下來看看。
實踐1:參數以by value 方式而非by reference 方式傳遞

View Code
實踐2、3:final的用法 略
實踐4:在arrays和vectors之間慎重選擇
數組在java中使用率遠遠超過vector,是以這裡就要明白何時應該使用vector
首先vector是線程安全的,這樣就保證了他可以同步控制對象,
其次vector内部實作也是數組,隻不過是泛型對象的數組(數組更多時候存儲的是基礎類型)
最後就是數組的大小是無法自行拓展的,而vector是可以通過System.arraycopy()方法進行複制擴充vector的容量
實踐5:多态優于instanceof
這裡必須明白java多态和instanceof用法,簡單說下兩者的概念
所謂的多态就是不同對象對同一個消息作出不同的響應,java中的多态包含了重載和重寫(覆寫)
instanceof 運算符是用來在運作時指出對象是否是特定類的一個執行個體,通過傳回一個布爾值來指出,這個對象是否是這個特定類或者是它的子類的一個
先看下面一個例子
上面例子中 程式員在計算工資的時候是需要考慮獎金的,是以通過Instanceof來判定傳給
calcSalary方法的參數是否是Programmer類,如果是
則在原有工資計算方法上加上bonus()方法
表面上看,這樣的邏輯沒有問題,但是我們是需要考慮拓展的,加入現在還有産品經理,他的工資也有獎金
另外還有其他福利,在加上其他崗位
那麼每增加一個崗位的變動
我們都需要去修改calcSalary方法,而這樣的設計明顯是不符合java的規範的
書本作者給出的方案是讓經理也有獎金的方法,這不過這個獎金是0
進而避免了instanceof的産生,具體做法看書本,此處略
實踐6:必要時才需要instanceof
java支援父類向下轉型,即使是錯誤的向下轉型
在編譯的時候是不會報錯的,是以容易讓開發人員帶來幹擾
實踐7:一旦不再需要object reference,就将它設為null
接觸java的都明白java自帶的虛拟機有垃圾回收機制,不願太操心記憶體問題,其實作為一名合格的javaer也是需要考慮記憶體洩露的
況且java确實有存在,當然這裡不再我們的讨論話題中,為什麼沒用的引用盡量要手動的去觸發unusefulObj=null呢
其實就是減輕JVM的工作量,gc不是随時觸發的 這個應該要懂得
執行個體中的例子已經很不錯了

實踐8:差別reference類别和primitive型别
這個可能比較拗口很難了解字面的意思,其實也是實踐1所說的基礎類型和對象引用之間的差別
這裡主要是介紹下java1.5的一個新特性:拆箱和裝箱
Integer i1=100;//等同于new Integer(100) 這裡就是一個自動裝箱的過程
int k=i1;// 自動拆箱的過程
更多關于拆箱與裝箱
可以移步http://www.cnblogs.com/danne823/archive/2011/04/22/2025332.html
關于包裝類的緩存:http://blog.csdn.net/yaoweijq/article/details/6021706
實踐9:區分==和equals
這個是java經常碰到的一個基礎知識點,即"=="和"equals"差別,何時使用==何時使用equals
總結起來可以這麼說:== 對于基礎類型 比較的是vlaue,而引用類型比較的是位址,當對象不需要單純的比較位址
而需要你自己DIY的時候,請重寫equals方法吧
至于何時使用,可以這麼說:==經常是基礎類型在用,引用類型的基本不用
equals最常見,而且多數情況下你是需要重寫的
有點以偏概全,希望拍磚
實踐10:不要依賴equals()的預設實作
不啰嗦了,直接上代碼

上面算是比較正常的一個重寫equals的方法,後續書本作者也提到了一個情況
就是對象的變量如果不是基礎類型,也是引用類型的話,就需要額外處理了(舉個例子,比如brand改成Stringbuffer類型)
作者給出了四個解決辦法:
1.不使用Stringbuffer,繼續使用String 2.比較的時候 先将Stringbuffer對象轉出String(調用toString()方法) 3.繼承Stringbuffer,重寫equals方法 讓變量變成重寫類的類型(有點拗口) 4.放棄equals改用compare()方法
例子書本上都有,感興趣的都可以去看看
關于何時重寫equals,上一節已經表述了自己的觀點,這裡補充下原作者的觀點:
實踐11~15 略
實踐16:認識【異常控制流】機制
記住一個模式:try { //do something }catch(Exception e){// when exception happen
to do }finally{//不管有無異常 都将執行 不受return 影響}
順序為:先執行try中的邏輯,如果正常執行,則跳轉到finally塊中執行,如果異常了,則會終止try塊中的邏輯,轉移到
catch塊中執行,最後還是會在finally完成最後的操作

實踐17:絕對不可輕視異常
當發生程式異常的時候,我們有哪些處理方式
1.捕獲并處理,防止它進一步傳播 2.捕獲并在此抛出它,傳播給它的調用者 3.捕獲它,并抛出一個新的異常給調用者 4.不捕獲這個異常,任由它傳播
這裡需要用到引用一個新的概念:抛出異常,通過throws來完成
正常情況下,第一個處理方式是最常見的,實踐16中也是采用了第一種處理方式
後續三種我們将在實踐18~20中一一介紹

實踐18:千萬不要遮掩異常
在處理try塊彙總的異常時,如果catch擷取finally中又抛出異常,那麼之前的異常會被覆寫
優先級:finally>catch>try
我們知道,finally是不受之前是否異常影響的,都将會執行,但是特殊情況下finally語句照樣
也會産生異常,那到底要如何處理呢?那就是将異常存放在Vector中

實踐19:明确throws字據的缺點
我們在開發過程中,經常會調用一些公用的函數(作者給了一個很通俗的名稱:工蜂型函數),而這些函數
有可能會産生異常(比如調用資料庫連接配接的方法),這時候處理異常有兩種方式
一種是函數自身處理,一個是調用端來處理.個人偏好是函數本身來處理,否則有10處地方調用這個函數
就要捕獲10次
實踐20:細緻而全面的了解throws子句
看的不是很懂,但是根據作者的demo,我了解的是作者想表達的意圖是當重寫函數的時候
函數抛出的異常範圍不能大于該函數抛出範圍,當然也可以不抛出異常(子類抛出異常的範圍不能大于父類)

實踐21:使用finally避免資源洩露
簡單的描述就是在異常進行中,java規範是通過finally來做一些善後的事情(包括釋放資源等)
實踐23:将try/catch區段置于循環之外
弦外音:不能循環調用try/catch區段,而應該在一個try/catch中調用循環
實踐27:抛出異常前線将對象恢複為有效狀态
弦外音:将狀态變量等處理放在可能處理異常之後,保證狀态不受異常影響
實踐31:如欲進行字元串結合,StringBuffer優于String
弦外音:對于需要頻繁處理字元拼接組合的地方,請使用StringBuffer,或則對于稍微複雜的操作,請使用StringBuffer
實踐33:慎防未使用的對象
弦外音:如果一個判斷兩選一,請不要都建立之,然後根據if else 來選擇其中一個對象
換句話說,使用的時候才去建立對象
實踐34:将同步化降至最低
弦外音:盡量少用同步操作,諸如synchronized等,除非你需要同步資源
實踐35:盡可能使用stack變量
弦外音:盡量使用局部變量(stack)來代替全局變量(heap)
實踐36:使用static,final和Privatae函數以促成inlining
略,後續在認真看
略,對多線程感興趣的朋友可以看看,都比較基礎
實踐59.運用接口來支援多繼承
弦外音:java雖然不支援多繼承(class a extends b,c)但是卻可以通過接口
來完成多實作(class a implements a,b ,c......)
實踐60.避免接口函數發生沖突
弦外音:假如類A實作了B,C兩個接口,但是B和C都有方法test()
這樣A要實作B還是C的test()方法呢,作者給出了解決方式,個人覺得方法很贊
java中很多庫都使用了類似的方式來解決這類問題
即讓D繼承B接口(重命名接口,避免沖突),然後class A Implements D,C
實踐61、62:
關于繼承和接口 抽象類等知識點
實踐63~66
關于類引用之間的操作 包括淺克隆 深克隆等
實踐68:在構造函數内調用non-final函數是要當心
這個記得初學java時候,比較難搞懂的一道題目,了解其機制
需要明白java對一個類的初始過程
我們結合代碼來看下
PDF和筆記源碼稍後上傳