首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

《Effective Java》學習筆記(一):創建與銷毀對象 — 靜態工廠、單例、不可實例化、避免重複創建、消除過期引用、慎用終結器

     編輯:Java 相關知識

前言

《Effective Java》被譽為 Java 程序員的「必讀經典」,地位等同《Effective C++》。本系列筆記記錄核心條目精華,助力進階。第一章聚焦對象生命週期管理。

第 1 條:考慮靜態工廠方法代替構造器

範例: Boolean.valueOf(boolean) 返回預緩存 Boolean.TRUE/FALSE,不創建新對象。

優點:

  1. 有名字:BigInteger.probablePrime 比構造器語義清晰;多構造器參數順序易混淆時尤佳。
  2. 不必每次創建對象:單例、不可變類緩存、享元模式。
  3. 可返回子類型:Collections 靜態工廠返回 20 多種 Collection 實現,API 隱藏具體類。
  4. 缺點:

    1. 無 public/protected 構造器 → 無法子類化(間接限制繼承濫用)。
    2. 不易發現:需在文檔明確標註,慣例命名 valueOf/of/getInstance/newInstance/getType。
    3. 建議: 無強烈理由優先用構造器;需控制實例數量、返回子類型、語義化時用靜態工廠。

      第 2 條:私有構造器強化 Singleton

      兩種寫法:

      1. public final 域(常量模式)

      public class Elvis {
          public static final Elvis INSTANCE = new Elvis();
          private Elvis() { ... }
      }

      2. 靜態工廠方法(可控制是否單例、延遲初始化)

      public class Elvis {
          private static final Elvis INSTANCE = new Elvis();
          private Elvis() { ... }
          public static Elvis getInstance() { return INSTANCE; }
      }

      序列化陷阱: 僅實現 Serializable 不夠,反序列化會產生新實例。必須提供 readResolve:

      private Object readResolve() { return INSTANCE; }

      第 3 條:私有構造器強化不可實例化

      工具類(如 java.util.Arrays、Collections)不應被實例化。抽象類無效(可被子類實例化)。唯一解法:顯式私有構造器:

      public class UtilityClass {
          private UtilityClass() { throw new AssertionError(); } // 防止反射調用
          public static void doSomething() { ... }
      }

      副作用:也禁止了繼承(子類無法調用 super())。

      第 4 條:避免重複創建對象

      • 不可變對象可重用:String s = "denny" 而非 new String("denny")。
      • 靜態常量緩存:正則 Pattern、DateFormat 等重量級對象聲明為 private static final,在靜態塊初始化。
      • 自動裝箱陷阱:Long sum = 0L; for(...) sum += i; 每次創建 Long,改用 long 基本類型。
      • 輕量對象創建廉價:別過度優化小對象;重量級資源(DB 連線、線程)才需對象池。

      第 5 條:消除過期引用

      內存洩漏在 Java 也存在。經典棧實現:

      public Object pop() {
          if (size == 0) throw new EmptyStackException();
          Object result = elements[--size];
          elements[size] = null; // 關鍵:消除過期引用
          return result;
      }

      其他洩漏源:緩存(需 WeakHashMap 或定時清理)、監聽器/回調未移除、ThreadLocal 未清理。工具:JProfiler、VisualVM、MAT 分析堆轉儲。

      第 6 條:避免使用終結器 finalize()

      • 執行時間不確定:對象不可達到 finalize 執行間隔任意,不適合時間敏感資源釋放(關閉文件、釋放鎖)。
      • 異常吞沒:finalize 拋出異常會被忽略,導致對象損壞狀態持久化。
      • 效能開銷:需兩次 GC 週期回收。
      • 移植性差:JVM 實現差異大。

      正確做法:顯式終止方法 + try-finally

      InputStream in = new FileInputStream(file);
      try { ... } finally { in.close(); } // 或 Java 7 try-with-resources

      finalize 合理用途:

      1. 安全網:客戶忘記調用 close() 時最後嘗試釋放非關鍵資源。
      2. 原生對象清理:JNI 分配的無關鍵資源。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved