「你應該進行防禦性編程,假設你的類別的客戶將盡最大努力破壞其不變量」
Java 作為一種安全語言:
- Java 可以防止 C/C++ 中常見的記憶體錯誤,但不能完全隔離類別與其他類別之間不必要的互動。
- 假設類別的客戶端可能試圖違反其不變量,則需要進行防禦性程式設計。
不可變類與安全性:
- 類別「Period」的範例,它看似不可變,但可能由於日期等物件的可變性而被損壞。
- 解決方案:在建構函式中接收可變參數時,製作可變參數的防禦性副本。
public Period(Date start, Date end) {
this.start = new Date(start.getTime()); // Cópia defensiva
this.end = new Date(end.getTime());
if (this.start.compareTo(this.end) > 0)
throw new IllegalArgumentException(start + " after " + end);
}
登入後複製
建構器中的防禦副本:
- 在驗證參數之前必須製作防禦副本,以避免漏洞(例如 TOCTOU 攻擊)。
- 避免使用clone()來保護潛在不受信任的物件的副本,首選靜態建構子或工廠方法。
吸氣劑和可變性:
- 問題:Getter 可以暴露可變的內部組件,從而允許外部突變。
- 解決方案:Getter 應該傳回可變物件的防禦性副本。
public Date getStart() {
return new Date(start.getTime()); // Cópia defensiva
}
登入後複製
應用於可變類:
- 防禦性複製也適用於儲存對客戶端提供的可變物件的參考的可變類別。
- 範例:在 Set 或 Map 中儲存物件時,必須考慮該物件以後是否可以修改。
內部組件回傳:
使用不可變物件:
- 只要有可能,就使用不可變物件作為內部元件,以避免需要防禦性副本。
成本與替代方案:
- 防禦性副本會影響效能;替代方案包括依賴文件或明確的使用協定。
- 在明確轉移控制的情況下,例如在設計模式中(例如包裝器),可以省去防禦性副本。
結論:
- 使用防禦性副本來保護類別的完整性,除非成本不切實際或建立了相互信任並且需要清晰的文件。
書中的範例:
以上是項目 必要時製作防禦性副本的詳細內容。更多資訊請關注PHP中文網其他相關文章!