| 優勢 | 說明 |
| 資料保護 | 防止無效/非法資料寫入(如年齡負數、空字串名稱) |
| 實現隱藏 | 內部儲存方式變更(如改用 Map、資料庫)不影響呼叫端 |
| 靈活控制 | 可實現唯讀(僅 getter)、唯寫(僅 setter)、延遲載入 |
| 除錯便利 | 在 setter 中設斷點/日誌,追蹤資料變更來源 |
| 框架相容 | JavaBean 規範、ORM、序列化、JSON 轉換均依賴 getter/setter |
標準 JavaBean 範例
public class Book {
private int id;
private String name;
private double price;
private String author;
// 無參建構子(框架反射實例化必需)
public Book() {}
// 全參建構子(方便建立物件)
public Book(int id, String name, double price, String author) {
this.id = id;
this.name = name;
this.price = price;
this.author = author;
}
// Getter/Setter
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) {
this.name = name != null ? name.trim() : null; // 防禦性處理
}
public double getPrice() { return price; }
public void setPrice(double price) {
if (price < 0) throw new IllegalArgumentException("價格不能為負數");
this.price = price;
}
public String getAuthor() { return author; }
public void setAuthor(String author) { this.author = author; }
}
進階封裝模式
1. 唯讀屬性(不可變物件)
public final class ImmutablePoint {
private final int x;
private final int y;
public ImmutablePoint(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() { return x; }
public int getY() { return y; }
// 無 setter,物件建立後狀態不可變
}
2. 延遲初始化
public class ExpensiveResource {
private HeavyObject heavyObject;
public HeavyObject getHeavyObject() {
if (heavyObject == null) {
synchronized (this) {
if (heavyObject == null) { // 雙重檢查鎖
heavyObject = new HeavyObject();
}
}
}
return heavyObject;
}
}
3. 防禦性複製
public class Period {
private final Date start;
private final Date end;
public Period(Date start, Date end) {
// 建構子防禦性複製
this.start = new Date(start.getTime());
this.end = new Date(end.getTime());
if (this.start.compareTo(this.end) > 0)
throw new IllegalArgumentException("開始時間不能晚於結束時間");
}
public Date getStart() {
// Getter 防禦性複製,防止外部修改內部狀態
return new Date(start.getTime());
}
public Date getEnd() {
return new Date(end.getTime());
}
}
IDE 自動生成技巧
- Eclipse:
Alt + Shift + S → Generate Getters and Setters
- IntelliJ IDEA:
Alt + Insert → Getter and Setter
- 可勾選生成
toString()、equals()/hashCode()、建構子
常見誤區
| 誤區 | 正確認知 |
| 所有類別都要為每個屬性生成 getter/setter | DTO/VO 需要,領域模型應暴露行為而非資料(告訴物件做什麼,別問物件有什麼) |
| setter 僅做單純賦值 | 應包含驗證、轉換、副作用處理 |
| 回傳可變物件引用 | 回傳副本或不可變視圖(Collections.unmodifiableList()) |
| boolean 型屬性用 getXxx() | 慣例用 isXxx()(如 isActive()) |
Lombok 簡化封裝
@Data // 包含 @Getter @Setter @ToString @EqualsAndHashCode @RequiredArgsConstructor
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class User {
private Long id;
private String username;
private String email;
@Setter(AccessLevel.NONE) // 唯讀,僅建構子設定
private LocalDateTime createdAt;
}
編譯期自動生成標準存取器,減少樣板程式碼,但需理解其生成邏輯。
總結
封裝不只是「私有屬性 + getter/setter」,而是資料保護、實現隱藏、介面契約的綜合體現。良好的封裝讓類別成為堅固的模組,支援系統演進與維護。掌握防禦性複製、不可變模式、延遲初始化等進階技巧,能寫出更健壯的 Java 程式碼。
- 上一篇文章: Java Collections 工具類常用 API 實戰指南
- 下一篇文章: Java Timer 定時器完整指南:從基礎到企業級應用
Copyright ©
程式碼之家 All Rights Reserved