《Effective Java 中文版》- 20240715

1. 用靜態方法替代構造器(五個優點、兩個缺點)。

相比于構造器,優點如下:

  • 有名稱;
  • 不用再每次調用時返回一個新的對象;
  • 可以返回聲明類型的子類型的對象;適用于基于接口的框架;
  • 每次調用時,可以基于不同的參數返回不同的對象實例;
  • 所返回對象的類并不一定要存在;這種靈活的靜態工廠方法提供了靈活的服務提供者框架;
    相比于構造器,缺點如下:
  • 如果沒有公共的或者受保護的構造器,就不能為其生成子類;

子類構造器會自動調用父類構造器,所以當父類沒有構造器為其調用時,就沒有辦法創建子類;

  • JavaDoc生成文檔時,對其展示沒有構造器明顯;
2. 當構造函數的參數比較多時使用生成器。
  • Builder類作為使用類的靜態內部類,其字段為外部類可能需要的構造參數;
  • 可以防止復雜對象在構造過程中被破壞;
  • 同一個生成器可以用來生成多個相同的對象(享元);
3. 利用私有構造器或者枚舉類型強化Singleton屬性;
public class Elvis  {
    public static final Elvis INSTANCE = new Elvis();
    private Elvis() {...}
    // ...
    // 第二種
    private static final Elvis INSTANCE = new Elvis();
    public static Elvis getInstance () { return INSTANCE; }

    // 此處的作用:防止Singleton的對象序列化后,再反序列化會生成新的對象,
    // 破壞了Singleton的設計;
    private Object readResolve() {
        return INSTANCE; // 讓GC處理假的Elvis對象;
    }
}
4. 利用私有構造器防止類被實例化;(上面??的代碼有示例)
5. 優先考慮通過依賴注入來鏈接資源;

對于行為會被底層資源以參數化的方式影響的類而言,靜態工具類和Singleton類都不合適;

// 依賴注入:即將依賴資源通過參數的形式傳遞到類的構造器中
public class SpellChecker {
    private final Lexicon dictionary;
    public SpellChecker(Lexicon dictionary) {
        this.dictionary = Object.requiredNonNull(dictionary); 
    }
}
6. 避免創建不必要的對象;
  • 比如正則處理會生成Pattern對象,對性能要求高的場景,可以預先生成Pattern對象;
  • 自動裝箱也會生成可能不必要的對象;所以優先使用基本類型而不是其封裝類,并提防無意中的自動裝箱;
7. 及時清理掉過期的引用;
8. 承接上一點,避免使用終結(finalizer)方法和清理(cleaner)方法;
  • 兩個方法清理不夠及時,甚至不保證會運行;
  • 終結過程中發生的異常會被忽略,導致其他對象可能處于損壞狀態;
9. 與try-finally相比,首選try-with-resources;
10. 重寫equals方法;

需要遵守五個約定:

  • 自反性:x.equals(x);
  • 對稱性:x.equals(y) 與 y.equals(x)結果相同;
  • 傳遞性:x.equals(y) && y.equals(z) => x.equals(z);
  • 一致性: 無論何時調用,x.equals(y)的結果不變;
  • 非空性:x.equlas(null) 返回false;
    編寫高質量equals方法的技巧:
  • 使用 ==檢查參數是否指向當前對象的引用;
  • 使用 instanceof 運算符檢查參數是否具有正確的類型;
  • 將參數轉換為正確的類型;
  • 對于類中每個“重要”的字段,檢查參數的這些字段是否與當前對象相應字段匹配;
11. 重寫equals方法時應始終重寫hashcode方法;
  • equals相等,hashcode一定相等;
  • hashcode相等,equals不一定相等;
  • hash算法應盡可能返回分散的散列值,以避免hash沖突,導致檢索性能較低;
12. 總是重寫toString() 方法;
  • 可以增強debug或者日志中類的可讀性;
13. 謹慎重寫clone方法;
  • clone的實現可能會是一個淺拷貝;
  • clone充當了構造器的作用,必須確保它不會對原始對象造成傷害,并確保它在克隆體上正確建立不變式;
  • 大多數情況,提供復制構造器會是更好的選擇;
public class Yum {
    public Yum(Yum yum) {
    // ...
    }
}

14. 考慮實現Comparable接口;

  • 當類可能需要一些比較操作時可考慮實現;
  • 盡量使用系統提供的基于靜態的比較器,或者基于比較器構造方法的比較器;
// 基于靜態的比較器
static Comparator<Object> hashCodeOrder = new Comparator<>() {
    public int compare(Object o1, Object o2) {
        return Integer.compare(o1.hashCode(), o2.hashCode());
    }
}
// 基于比較器構造方法
static Comparator<Object> hashCodeOrder = Comparator.compareInt(o -> o.hashCode());
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容