一、什么是多态
一句话:同一条消息,被不同对象接收时表现出不同行为。
在 Java 中,实例方法天生就是多态的:
Bird b = new Bird();
Plane p = new Plane();
fly(b); // 挥动翅膀
fly(p); // 启动引擎
fly 方法的“接收者”决定了最终执行哪段代码,而参数则在编译期静态绑定——多态只关心“谁接收消息”,不关心“参数是谁”。
注意:
• static 方法没有多态,它在编译期就与类绑定。
• null instanceof AnyClass 永远返回 false,避免空指针误判。
二、多态带来的设计红利——策略模式
- 问题:一段冗长的 if-else 计算折扣
switch(strategy){
case "NoDiscount": ...
case "95": ...
case "VIP": ...
}
新增一种折扣就要改方法,违背开闭原则。
- 解决:把“变化”封装成策略家族
• 抽象策略
public interface DiscountStrategy {
int discount(int price, User user);
}
• 具体策略
public class NoDiscountStrategy implements DiscountStrategy {
public int discount(int price, User user) { return price; }
}
public class Vip95Strategy implements DiscountStrategy {
public int discount(int price, User user) {
return user.isVip() ? (int)(price * 0.95) : price;
}
}
• 上下文
public class PriceCalculator {
public int calculate(DiscountStrategy strategy, int price, User user) {
return strategy.discount(price, user);
}
}
新增策略 = 新建一个类,上下文代码零修改,彻底解耦。
三、JDK 中的策略模式范例——线程池拒绝策略
ThreadPoolExecutor 最后一个参数 RejectedExecutionHandler 就是策略接口:
public interface RejectedExecutionHandler {
void rejectedExecution(Runnable r, ThreadPoolExecutor executor);
}
JDK 自带 4 种实现:AbortPolicy / CallerRunsPolicy / DiscardOldestPolicy / DiscardPolicy。
• 想自定义?只需实现接口,线程池无需任何改动。
• 面试高频:为什么线程池要抽象出 RejectedExecutionHandler?答案——策略模式带来的独立变化与松耦合。
四、用多态重构“胖”代码
实际项目中,任何出现大片 if-else/switch 且分支逻辑与业务强耦合的地方,都可以:
- 提取公共接口或抽象类;
- 把每个分支变成具体策略;
- 通过工厂 + 多态注入。
IntelliJ IDEA 的 Diagrams 功能可以一键查看继承树,辅助我们验证设计是否合理。
五、金额表示的友情提醒
金融场景千万别用 double!1.0-0.9≠0.1。统一用 BigDecimal 或“分”为单位 long 型,避免精度灾难。