《Effective Java中文版第二版》讀書筆記
說明
這裏是閱讀《Effective Java中文版第二版》的讀書筆記,這裏會記錄一些個人感覺稍微有些重要的內容,方便以後查閱,可能會因為個人實力原因導致理解有誤,若有發現歡迎指出。一些個人還不理解的會用斜線標註。
第一章是引言,所以跳過。
第二章 創建和銷毀對象
第1條:考慮用靜態工廠方法代替構造器
含義
靜態工廠方法是指一個返回類的實例的靜態方法,例如:
public static Boolean valueOf(boolean b) {
return b ? Boolean.TRUE : Boolean,FALSE;
}
優點
相對於一個類的構造器,靜態工廠方法的名稱沒有限制。
眾所周知,構造器的方法名是必須和類名一樣的,因此對於有多個參數類型相同的構造方法,一種方法是更改參數的順序,另一種是增加一個flag來判斷執行哪個構造方法。但是這樣對於使用者是不友好的,他必須熟悉API或者查閱開發文檔。倘若使用靜態工廠方法,那麽可以通過方法名來給予使用者良好的提示與說明。
不用再每次調用的時候創建一個新的對象。
這句話的典型應用是在設計模式的單例模式中,靜態工廠方法能夠為重復的調用返回相同的對象。
靜態工廠方法可以返回原返回類型的任何子類型的對象。
構造方法是不能使用return語句的,它在使用時也只能產生自身這個類的一個對象,而靜態工廠方法可以使用return語句,因此在選擇返回對象時就有了更大的靈活性。這個優勢的應用很多,比如服務提供者框架模式。
小結
應當熟悉靜態工廠方法和構造器的各自的長處,在合適的場景使用合適的方法。
第2條:遇到多個構造器參數時要考慮用構建器
在面對一個擁有多個屬性的類且構造方法擁有多個可選參數時,一個常見的方法是使用重疊構造器模式(創建多個構造方法,每個構造方法比前一個構造方法有新的參數)。例如,第一個構造方法有兩個必須參數,第二個構造方法有兩個必須參數和一個可選參數,第三個構造方法有兩個必須參數和兩個可選參數,以此類推。但是當有許多參數的時候,代碼會變得很難編寫,也很難閱讀,甚至會容易出錯。
另一個方法是使用javabean模式。因為構造過程被分到了多個調用中(為每個屬性的賦值調用該屬性的set方法),在構造過程中,javabean可能處於不一致的狀態,這種問題難以發現。
第三種方法就是構建器模式(Builder模式)的一種形式。
public class NutritionFacts {
private final int servingSize;
private final int servings;
private final int calories;
private final int fat;
private final int sodium;
private final int carbohydrate;
public static class Builder {
// 必須屬性
private final int servingSize;
private final int servings;
// 可選屬性
private int calories = 0;
private int fat = 0;
private int sodium = 0;
private int carbohydrate = 0;
public Builder(int servingSize, int servings) {
this.servingSize = servingSize;
this.servings = servings;
}
public Builder setCalories(int calories) {
this.calories = calories;
return this;
}
public Builder setFat(int fat) {
this.fat = fat;
return this;
}
public Builder setSodium(int sodium) {
this.sodium = sodium;
return this;
}
public Builder setCarbohydrate(int carbohydrate) {
this.carbohydrate = carbohydrate;
return this;
}
public NutritionFacts build() {
return new NutritionFacts(this);
}
}
private NutritionFacts(Builder builder) {
servingSize = builder.servingSize;
servings = builder.servings;
calories = builder.calories;
fat = builder.fat;
sodium = builder.sodium;
carbohydrate = builder.carbohydrate;
}
}
// 使用方法
NutritionFacts n = new NutritionFacts.Builder(200,10).setCalories(20).setFat(30).build();
Builder模式十分靈活,可以利用一個builder來創建多個相同的對象,並且對必須參數和可變參數的實現符合人類的正常思維。另外,對於使用者而言,使用時的代碼更容易閱讀和編寫。
這種方法我在google的protobuf的java實現中見到過。
第3條:用私有構造器或者枚舉類型強化Singleton屬性
私有構造方法就不提了,這裏記錄一下第二個:
public enum A {
INSTANCE;
public void leaveTheBuilding() {...}
}
第4條:通過私有構造器強化不可實例化的能力
對於一些只包含靜態方法或者靜態屬性的類(比如工具類),我們不希望他們被實例化。眾所周知,在缺少顯式構造方法的時候,編譯器會默認添加一個無參的構造方法。如果為了嚴謹,我們可以添加一個私有的構造方法,更可以在這個構造方法中throw異常來中止程序。
第5條:避免創建不必要的對象
一般來說,最好能重用對象而不是在每次需要的時候就創建一個相同功能的新對象。
除了重用不可變的對象之外,也可以重用那些已知不會被修改的可變對象。
能使用基本數據類型,就盡量不要用對應的封裝類。
第6條:消除過期的對象引用
不能以為有了垃圾回收機制後,就不需要考慮內存管理的事情了。
例如用數組來實現棧,當實現出棧操作,size-1後,棧頂坐標後的元素對使用者來說就已經是無效部分了,但是數組仍然擁有對它們的引用,因此垃圾回收機制不會將它們回收。解決辦法是在出棧時,將引用置空。
第7條:避免使用終結方法
除了特定情況,不要使用終結方法(finalize)。
子類覆蓋了父類的終結方法後,子類的終結方法不會自動調用父類的終結方法,需要手動調用。
《Effective Java中文版第二版》讀書筆記