




多态不是语法糖,而是设计能力的放大器;适用场景是运行时需动态决定同一语义范畴的行为且未来大概率新增,如支付策略;误用if-else式重写、错选抽象类/接口、调用失败因null/static/final/签名不一致等均违背其初衷。
Java多态不是语法糖,而是设计能力的放大器——用错地方会掩盖类型契约,用对了才能让扩展不改旧代码。
核心判断标准:是否需要在运行时动态决定行为,且这些行为属于同一语义范畴(比如“计算折扣”“发送通知”“解析格式”),同时未来大概率要新增同类行为。
PaymentStrategy 接口下有 AlipayStrategy、WechatPayStrategy、CreditCardStrategy,新增 Apple Pay 只需加个新类,不碰原有 pay() 调用逻辑ACTIVE/INACTIVE 两种,且逻辑极其简单(如只设一个字段),硬套策略模式反而增加认知负担if (type == X) { ... },这等于把 switch 搬进了方法里,违背了多态初衷关键看“有没有共享状态或默认行为”。Java 8+ 后接口可有 default 方法,但不能有构造器、字段(除 public static final),也不能有 protected 成员。
protected 工具方法、或存在必须由父类控制的生命周期钩子(如 templateMethod() 中调用 beforeExecute() 和 afterExecute())Comparable、Runnable),或需要被不相关的类实现(如 Serializable 与业务逻辑无关)default 方法来模拟抽象类,结果导致接口职责膨胀,违反单一职责;或者把本该是接口的契约强行做成抽象类,导致子类被迫继承无用字段编译通过但运行时没走预期子类方法?先查这三项:
null —— 调用时抛 NullPointerException,而非进入子类逻辑static、final 或 private 修饰 —— 多态只适用于实例的非静态、非 final、非 private 方法void process(String data),子类写成 void process(Object data),这其实是重载(overload),不是重写(override),JVM 不会动态分派
// 错误示例:看似重写,实为重载
class Processor {
void handle(List items) { System.out.println("base"); }
}
class JsonProcessor extends Processor {
// 注意参数类型变了!这是重载,不是重写
void handle(List
一旦出现 if (obj instanceof Xxx) { Xxx x = (Xxx) obj; x.specificMethod(); },说明抽象不够彻底,或者职责没划清。
specificMethod() 提到父类/接口中,哪怕子类实现是空方法或抛 UnsupportedOperationException(需文档说明)
最常被忽略的一点:多态的代价不在性能(现代 JVM 的虚方法调用优化已很成熟),而在于调用链路变长后,IDE 很难静态推导出最终执行的是哪个实现——这意味着你得靠测试和文档来守住行为边界,而不是靠编译器。