相關讀書筆記列表
NO.4 避免建立重複的對象
如果一個對象是非可變的,那麼他中上可以被重用的,如:
- //不推薦,"test"本來就是一個String執行個體,如果此方法在一個迴圈中或者被頻繁的調用,將會嚴重影響效能
- String s = new String("test");
- //推薦方式
- String s = "test";
對於提供靜態方法和建構函式的非可變類,推薦使用靜態方法,這樣可以避免重複建立對象,如:Boolean.vauleOf(String)方法優於建構函式Boolean(String)
如下Person類在每次調用isBabyBoomer()方法時都需新建立對象,極大的影響了效能
- import java.util.*;
- public class Person {
- private final Date birthDate;
- public Person(Date birthDate) {
- // Defensive copy - see Item 39
- this.birthDate = new Date(birthDate.getTime());
- }
- // Other fields, methods omitted
- // DON'T DO THIS!
- public boolean isBabyBoomer() {
- // Unnecessary allocation of expensive object
- Calendar gmtCal =
- Calendar.getInstance(TimeZone.getTimeZone("GMT"));
- gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0);
- Date boomStart = gmtCal.getTime();
- gmtCal.set(1965, Calendar.JANUARY, 1, 0, 0, 0);
- Date boomEnd = gmtCal.getTime();
- return birthDate.compareTo(boomStart) >= 0 &&
- birthDate.compareTo(boomEnd) < 0;
- }
- }
改進方案如下:
- import java.util.*;
- class Person {
- private final Date birthDate;
- public Person(Date birthDate) {
- // Defensive copy - see Item 39
- this.birthDate = new Date(birthDate.getTime());
- }
- // Other fields, methods
- /**
- * The starting and ending dates of the baby boom.
- */
- private static final Date BOOM_START;
- private static final Date BOOM_END;
- static {
- Calendar gmtCal =
- Calendar.getInstance(TimeZone.getTimeZone("GMT"));
- gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0);
- BOOM_START = gmtCal.getTime();
- gmtCal.set(1965, Calendar.JANUARY, 1, 0, 0, 0);
- BOOM_END = gmtCal.getTime();
- }
- public boolean isBabyBoomer() {
- return birthDate.compareTo(BOOM_START) >= 0 &&
- birthDate.compareTo(BOOM_END) < 0;
- }
- }
這樣類變數在類在初始化建立Calendar、Date、TimeZone時只需建立一次,已經初始化的不再進行初始化操作,效能好於前一種方法一百倍。【static變數在系統沒有調用isBabyBoomer() 方法之前,不會進行初始化(延遲初始化)】
類初始化的順序:先初始化父類的靜態代碼--->初始化子類的靜態代碼-->初始化父類的非靜態代碼--->初始化父類建構函式--->初始化子類非靜態代碼--->初始化子類建構函式。
NO.5 消除到期的對象引用
記憶體回收行程不會對“到期引用”(永遠不會在被解除的引用)的對象進行回收。如:數組中的元素先增加再減少這種情況,下標大於size()的那一部分就是到期引用的對象。
解決方案:
- public Object pop(){
- if(size == 0){
- throw new EmptyStackException();
- }
- Object result = elements[--size];
- //自減後把原來的引用置為null
- elements[size] = null;
- return result;
- }
優點:1、避免記憶體流失而造成的系統崩潰(記憶體流失也常見於緩衝,由於緩衝沒有及時清除無用的條目而出現,可以使用weakHashMap來避免這種情況,參考:利用WeakHashMap避免因緩衝條目到期而造成的記憶體流失問題);
2、程式能在第一時間拋出null 指標異常;
NO.6 避免使用終結函數 終結函數(finalizer)可以用來回收不可到達的對象,就是說對象的生命週期結束後,可以用終結函數來回收為該對象分配的資源。但是,終結函數執行線程的優先順序很低,以至於我們不敢把對時間要求比較高的對象回收讓終結函數來回收。JVM總是會延遲終結函數的執行。對於急需回收對象,可以使用tyr
finally,在finally寫回收對象的代碼,這樣就保證對象能及時被回收。 終結函數其實也是有用的。第一種情況是當作安全網,當忘了對對象顯示回收的時候,用終結函數作為最後的安全屏障。第二種情況是:普通對象通過一個本地方法
委託給本機物件叫本地對等體。本地對等體不是普通對象,所以當委託給他的對象被回收的時候本地對等體並不會被回收,所以這時候終結函數就派上用場了。最後要注意的是,當子類改寫覆蓋了超類的終結函數時候,如果不顯示調用超類的終結函數,那麼超類的終結函數將不會被執行。 總結:盡量不使用終結函數,除非作為安全網或者是用來回收不關鍵的本地資源。