Effective java第二版讀書筆記
阿新 • • 發佈:2018-11-01
下面對Effective java第二版中的技術點進行總結,未讀待續,先儲存著。
序號 | 技巧 | 優點 | 缺點及注意事項 |
---|---|---|---|
1 | 用靜態工廠方法代替構造器 | 有名稱, 不必在每次呼叫時都建立一個新物件,可返回原返回型別的任何子型別物件,建立引數化例項時,程式碼更簡潔 | 若類不含有公有或受保護的構造器,不能被子類化,它們與其他靜態方法實際上沒有任何區別 |
2 | 多個構造器引數時考慮用構造器 | Builder模式,利用所有必要的引數呼叫構造器,得到一個builder物件,再在builder物件上呼叫類似於setter方法 | 如果類的構造器或靜態工廠中有多個引數 |
3 | 用私有構造器或列舉型別強化Singleton屬性 | 1.私有構造器: public class Elvis { public static final Elvis INSTANCE = new Elvis(); private Elvis() {…} } 2. 列舉:public enum Elvis { INSTANCE; } |
Singleton指僅被例項化一次的類 |
4 | 通過私有構造器強化不可例項化的能力 | public class UtilityClass { private UtilityClass() {…} } | 只包含靜態方法和靜態域的類 |
5 | 避免建立不必要的物件 | 優先使用基本型別int, long, boolean等而不是裝箱基本型別Integer,Long, Boolean; 維持物件池; 物件能重用時儘量用同一物件,考慮用介面卡; | |
6 | 消除過期的物件引用 | 將過期物件設為null,使用弱引用WeakHashmap | |
7 | 避免使用終結方法 | 作為安全網或是為了終止非關鍵的本地資源時使用,仍要呼叫super.finalize | 不能保證會被及時執行;有效能損失; |
8 | 覆蓋equals時遵守的通用約定 | 自反性、對稱性、傳遞性、一致性、非空性 | 使用==檢查“引數是否為這個物件的引用”、使用instanceof操作符檢查“引數是否為正確型別” |
9 | 覆蓋equals時總要覆蓋hashCode | 相等的物件必須有相等的雜湊碼 | |
10 | 始終要覆蓋toString | 使類返回物件中包含值得關注的資訊 | 正常Object的toString返回的字串是“類名[email protected]+無符號十六進位制雜湊碼”,不是使用者期望的 |
11 | 謹慎地覆蓋clone | 實現了cloneable介面的類,必須要實現clone方法 | 克隆必須保證不會傷害到原始物件,確保正確地建立被克隆物件中的約束條件 |
12 | 考慮實現Comparable介面 | compareTo允許順序比較 | 若兩個被比較的compareTo物件引用不同類的物件,會拋異常 |
13 | 使類和成員的可訪問性最小化 | 儘可能使每個類或成員不被外界訪問,資訊隱藏 | 例項域不能是公有的,包含公有可變域的類不是執行緒安全的 |
14 | 在公有類中使用訪問方法而非公有域 | 對於可變類,應該用私有域和公有訪問(getter)/設值(setter)方法代替 | 若公有類暴露了它的資料域,將來想改變其內部表示法比較困難 |
15 | 使可變性最小化 | 不可變類即其例項不能被修改的類,主要有:不要提供任何會修改物件狀態的方法;保證類不會被擴充套件;使所有的域都是final的;所有域都成為私有 | 在特定情況下存在潛在的性以問題 |
16 | 複合優先於繼承 | 包裝類比子類更健壯,功能更強大;不會暴露太多實現細節 | 封裝違背了封裝原則 |
17 | 要麼為繼承而設計,並提供文件說明,要麼就禁止繼承 | 類文件必須精確地描述覆蓋每具方法所帶來的影響;構造器不能呼叫可被覆蓋的方法 | 對於並非為了進行子類化而設計和編寫文件的類,要禁止子類化,可以把類宣告為final型,或是把所有的構造器都變成私有的 |
18 | 介面優於抽象類 | 介面是定義mixin(混合型別)的理想民選擇;允許構造非層次結構的型別框架 | 介面一旦公開且被廣泛實現,再想改變幾乎不可能;(兩者區別:抽象類允許包含某些方法實現,介面不允許;類只能單繼承,實現抽象類只能成為一個子類,而介面不受此限制) |
19 | 介面只用定義型別 | 類實現介面時,介面就充當可以引用這個類的例項型別 | 介面應該只被用來定義型別,不應該被用來匯出常量 |
20 | 類層次優先於標籤類 | 類層次可以用來反映型別之間本質上的層次關係,有助於增強靈活性 | 若使用標籤類,域不能做成final型,且初始化出錯,很容易導致執行時失敗 |
21 | 用函式物件表示策略 | 函式指標是用來實現策略模式,為實現這種模式,需要宣告一個介面來表示策略,為每個具體策略宣告一個實現該介面的類 | |
22 | 優先考慮靜態成員類 | 如果宣告成員類不要求訪問外圍例項,就要始終把static修飾符放在它的宣告中 | 非靜態成員類的每個例項都隱含著與外圍類的一個外圍例項相關聯,保持這份引用需要消耗時間和空間 |
23 | 請不要在新程式碼中使用原生態型別 | 使用原生態型別,就失掉了泛型在安全性和表述性方面所有優勢 | List泛型;List無限制萬用字元型別,表示只能包含某種未知物件型別的一個集合;List原生態型別,脫離了泛型系統,不安全 |
24 | 消除非受檢的警告 | 每一條警告都表示可能在執行時丟擲ClassCastException異常 | 如果無法消除警告,且可證明引起警告的程式碼是型別安全的(可以使用@SuppressWarnings(“unchecked”)) |
25 | 列表優先於陣列 | 陣列在執行時才檢查元素型別約束,沒有編譯時的型別安全;泛型是通過擦除來實現,只在編譯時強化型別資訊,在執行時丟棄它們的元素型別資訊 | 擦除就是使泛型可以與沒有使用泛型的程式碼隨意進行互用,陣列和泛型不能很好的混合使用 |
26 | 優先考慮泛型 | 使用泛型比在客戶端進行型別轉換更安全,也更容易 | 把現有型別都泛型化 |
27 | 優先考慮泛型方法 | 使用泛型比在客戶端輸入引數和返回值的方法更安全,也更容易 | 像型別一樣,可以確保方法可以不用轉換就能使用 |
28 | 利用有限制萬用字元來提升API的靈活性 | 為獲取最大限度的靈活性,要在表示生產者或消費者的輸入引數上使用萬用字元型別 | 如Comparable優先於Comparable |
29 | 優先考慮型別安全的異構容器 | 將鍵進行引數化而不是將容器引數化,將引數化的鍵提交給容器 | 不可用在不可具體化的型別中,如List沒有對應的Class物件;客戶端很容易被破化型別安全,如使用原生態形式 |
30 | 用enum代替int常量 | 列舉所有的域都應該是final的,易讀,更安全,功能也更強大 | 列舉在裝載或初化時會有空間和時間的成本 |
31 | 用例項域代替序數 | 可以將列舉的序儲存在一個例項域中,如public enum Ensemble {SOLO(1), DUEP(2), …} | ordinal是為EnumSet和EnumMap型別的資料結構用的,為表示序號,不要用ordinal方法 |
32 | 用EnumSet代替位域 | EnumSet可從單個列舉型別中撮多個值的多個集合,批處理,如removeAll和retainAll,都是用位演算法實現的 | Java 1.6以前,無法建立不可變的EnumSet |
33 | 用EnumMap代替序數索引 | 如果要表示是關係是多維度的,就命名用EnumMap<…, EnumMap<…>> | EnumMap內部使用了陣列,集Map豐富功能和型別安全與陣列的快速於一體 |
34 | 用介面模擬可伸縮的列舉 | 定義一個介面,讓列舉實現這個介面 | |
35 | 註解優先於命名模式 | 拼寫錯誤,編譯期間就會發現;註解中陣列引數是優化的單元素陣列 | 命名模式的幾個缺陷:使用者單詞拼寫錯誤,不會報錯也不會執行,造成錯誤的安全感;無法確保它們只用於相應的程式元素上;沒有提供引數值與程式元素關聯的方法; |
36 | 堅持使用Override註解 | 如果想要覆蓋超類中宣告的方法,則使用Override註解 | 編譯器可以防止犯錯 |
37 | 用標記介面定義型別 | 可通過預設的方式新增一個或多個註解型別元素,給已被使用註解型別新增更多資訊 | 標記介面是指沒有包含方法宣告的介面,只是指明一個類實現了具有某種屬性的介面,如Serializable介面 |
38 | 檢查引數的有效性 | 非公有方法可以使用斷言來檢查它們的引數 | 設計引數限制檢查時,視具體需求而定,如果檢查很費時間或是導致操作非原子性,會加大程式執行時間 |
39 | 必要時進行保護性拷貝 | 保護性拷貝是在檢查引數有效性之前進行,有效性檢查的是拷貝之後的物件 |