“你应该进行防御性编程,假设你的类的客户将尽最大努力破坏其不变量”
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中文网其他相关文章!