里氏替换原则检验java继承层级的关键是子类能否在所有父类被使用处无缝替换且行为不变;需检查方法签名兼容性、前置条件不加强、后置条件不削弱、不变量与异常一致,并通过单元测试验证。

直接用里氏替换原则检验Java继承层级,关键不是看语法能不能编译通过,而是看子类能否在所有父类被使用的地方无缝替换,且行为不变。它检验的是设计契约,不是代码表面结构。
检查方法签名与返回类型是否兼容
子类重写父类方法时,参数类型不能变窄,返回类型不能变宽。Java支持协变返回(子类方法可返回父类返回类型的子类型),但不支持逆变参数。
- 允许:父类
Animal getPet()→ 子类重写为Dog getPet() - 禁止:父类
void feed(Object food)→ 子类改为void feed(DogFood food)(调用方传入CatFood会编译失败) - 注意:泛型擦除后,
List<string></string>和ArrayList<string></string>的方法签名需保持语义一致,不能因类型擦除掩盖契约破坏
验证前置条件未被加强
子类方法不能对输入施加比父类更严格的限制。如果父类方法接受任意整数,子类就不能只接受正数——否则依赖父类接口的代码传入负数时会意外失败。
- 反例:父类
void setSpeed(int kph)允许 -10(表示倒车),子类重写后抛出IllegalArgumentException当kph - 正解:子类可放宽约束(如支持更大范围),但不可收紧;若业务真需校验,应在父类契约中明确定义(如声明“仅支持非负值”)
确认后置条件未被削弱
子类方法执行后的结果、状态或副作用,必须满足甚至优于父类承诺。调用方依据父类文档做假设,子类不能打破这些假设。
- 父类方法文档写明“返回非null集合”,子类就绝不能返回
null或空集合(除非父类明确允许) - 父类保证“调用后对象进入‘就绪’状态”,子类不能跳过该状态或进入“错误”状态
- 涉及线程安全、事务边界、资源释放等隐式契约,同样适用——例如父类方法是原子的,子类不能拆成非原子操作
测试不变量与异常行为一致性
对象的关键不变量(如“余额 ≥ 0”“连接状态非空”)必须全程维持;异常抛出也需兼容——子类不能新增受检异常,运行时异常类型应保持语义一致。
- 父类
withdraw(double amount)声明抛出InsufficientFundsException,子类不得额外抛出NetworkTimeoutException(除非父类已声明) - 若父类从未抛出
NullPointerException,子类也不应因空指针提前崩溃——应按父类方式处理或转换为已有异常类型 - 可通过单元测试覆盖典型用例:用子类实例替换父类变量,运行原有父类测试套件,全部通过才算初步合规
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











