Java 对象契约
Java对象契约(Object Contract)指Java中所有对象必须遵守的行为规范,这些规范由Object类定义的核心方法约定构成,确保对象在集合操作、比较、多线程交互等场景下行为一致且可靠。以下是关键组成部分及其实质:
⚖️ 核心方法契约
- equals()方法
- 契约要求:
- 自反性:x.equals(x)必须返回true。
- 对称性:若x.equals(y)为true,则y.equals(x)也必须为true。
- 传递性:若x.equals(y)且y.equals(z),则x.equals(z)需成立。
- 一致性:多次调用结果相同(对象未修改时)。
- 非空性:x.equals(null)返回false。
- 若重写
equals()
但未同步重写hashCode()
,会违反契约(见下文)。
- 契约要求:
- hashCode()方法
- 契约要求:
- 若x.equals(y)==true,则
x.hashCode() == y.hashCode()
必须成立。 - 同一对象多次调用结果一致(未修改时)。
- 若x.equals(y)==true,则
- 风险场景:
- 未同步重写hashCode()时,两个逻辑相等的对象在HashMap中可能被存储到不同桶位,导致数据丢失或检索失败。
- 契约要求:
- toString()方法
- 隐含契约:返回清晰描述对象状态的字符串(非强制,但为最佳实践)。
- 默认实现(如
ClassName@hashCode
)通常需重写以提升可读性。
- clone()方法
- 契约要求:
- 需实现
Cloneable
标记接口(否则抛异常)。 - 默认实现为浅拷贝,需重写以实现深拷贝(如递归调用子对象clone())。
⠀
- 需实现
- 契约要求:
🔗 契约式设计(Design by Contract)的扩展
Java虽未原生支持契约式编程(DbC),但通过工具和注解模拟类似思想:
@Contract("null -> fail; !null -> !null") // 参数非空则返回非空
public String process(String input) {
return input.trim();
}
若传入null,IDE提示违反契约。
- Objects.requireNonNull() :显式守卫前置条件(如参数非空)。 ⠀
⚙️ 实际应用场景
- 集合框架
HashMap
依赖hashCode()
和equals()
定位键值对。违反契约会导致数据重复或丢失。HashSet
内部使用HashMap
,相同约束适用。
- 多线程协作
wait()
,notify()
,notifyAll()
的调用需在synchronized
块中,否则抛IllegalMonitorStateException
,这是隐含的线程安全契约。
- 对象序列化
- 实现
Serializable
接口(标记接口)即承诺对象可被序列化,需保证:- 所有字段可序列化
- 或标记为
transient
⠀
- 实现
💎 重要性总结
- 行为一致性 :确保对象在集合、比较、并发等场景下行为可靠。
- 框架兼容性 :Java集合、序列化、反射等机制依赖对象契约。
- 代码健壮性 :遵守契约可避免隐蔽Bug(如HashMap逻辑错误)。 ⠀⚠️ 关键提示 :重写equals()时必须同步重写hashCode(),否则破坏契约导致程序未定义行为。这是Java开发中最常见的契约违反场景之一。