里氏替换原则(lsp)是系统稳定性的底层约束,要求子类替换父类时调用方完全无感;违反将导致异常、逻辑错乱或静默失败;其核心在于设计阶段对语义、契约和结构的主动控制,确保继承反映真实is-a关系且行为一致。

里氏替换原则(LSP)不是用来“增强稳定性”的装饰性规范,而是系统稳定性的底层约束——它要求子类替换父类时,调用方完全感知不到变化。一旦违反,多态调用就可能触发异常、逻辑错乱或静默失败,稳定性直接崩塌。真正起作用的,是设计阶段对语义、契约和结构的主动控制。
只让真正“是一种”的类型继承
继承必须反映真实的 is-a 关系,且行为一致。不能因为“代码复用方便”或“分类上属于同一类”就强行拉进继承链。
- 合理:PaymentProcessor 是抽象父类,AlipayProcessor 和 WeChatPayProcessor 都支持统一 pay(amount) 方法,调用方传任意子类都不影响扣款流程
- 不合理:让 ElectricCar 继承 GasCar,仅因二者都是“车”;但 ElectricCar 的 refuel() 方法若抛 UnsupportedOperationException,调用方按 GasCar 逻辑调用就会崩溃
- 判断标准:把子类对象直接赋给父类引用后,所有父类方法调用仍符合原有语义和结果预期
用接口替代含伪能力的父类
当类型之间只有部分能力重合,而非全面兼容时,接口比继承更安全。它把“能做什么”显式声明,避免子类被迫实现不适用的方法。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 例如定义 Flyable 接口,含 fly() 方法;Bird 和 Drone 实现它,Penguin 不实现
- 客户端方法签名改为 void launch(Flyable flyer),编译期就排除了无法飞行的类型,无需运行时 instanceof 判断或 try-catch 降级
- 这样既保持多态,又杜绝了“子类重写后抛异常”这类典型 LSP 违反场景
守住方法重写的三条契约底线
子类重写父类方法时,必须同时满足前置不加强、后置不削弱、异常不扩大——这是 LSP 在代码层的硬性守则。
- 前置条件不加强:父类 void setAge(int age) 允许 0–150,子类不能改成 if (age
-
后置条件不削弱:父类 List
findUsers() 承诺返回非 null 集合,子类不能返回 null 或空 list(除非父类契约明确允许) - 异常不扩大:父类方法声明 throws IOException,子类可不抛异常,或只抛 FileNotFoundException(IOException 子类),但不可新增 SQLException
发现违例信号就果断重构
以下迹象说明继承结构已破坏 LSP,需立即干预,而不是靠文档或注释补救:
- 子类中大量出现 UnsupportedOperationException 或 “Not supported yet” 注释
- 调用方频繁使用 instanceof 或 getClass() 做类型判断再分支处理
- 测试用例中,父类通过但子类失败,或相同输入下父类与子类输出语义不一致
- 重构方向:把伪共性方法从父类移出;改用组合(如 Bird 持有 FlightBehavior);或拆成多个细粒度接口
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










