用interface或parentclass做形参本质是“为了不改代码”,即通过宽泛类型使方法不依赖具体实现,新增子类时无需修改方法签名和逻辑,从而实现开闭原则。

为什么用 Interface 或 ParentClass 做形参不是“为了多态”而是“为了不改代码”
多态参数的本质,是让方法不依赖具体实现,只关心“它能做什么”。比如你写了一个 processPayment(PaymentProcessor p),后续加了 AlipayProcessor、WechatPayProcessor,只要它们都实现了 PaymentProcessor 接口,就不用动 processPayment 的签名和逻辑。
常见错误现象:
– 传 new AlipayProcessor() 却声明形参为 AlipayProcessor,导致后续无法接入微信支付
– 在方法里用 instanceof 判断类型再强转,说明接口抽象不到位
- 接口比抽象类更轻量,优先选
interface(尤其当只是定义行为契约时) - 如果多个实现共享字段或默认逻辑,才考虑抽象父类
AbstractPaymentProcessor - 形参类型越宽泛越好,但不能宽到失去语义——比如别用
Object代替PaymentProcessor
addUser(User user) 能接收 Admin 和 Guest 吗?看继承关系是否成立
能接收的前提是:两个子类都继承自 User(或实现了同一接口),且方法签名明确使用 User 作为形参。
使用场景:
– REST 控制器接收 JSON 自动反序列化为 User 子类(需 Jackson 配置 @JsonTypeInfo)
– DAO 层统一处理不同角色的保存逻辑
立即学习“Java免费学习笔记(深入)”;
- 若
Admin继承User,而Guest没继承也不实现同一接口,则编译报错:incompatible types: Guest cannot be converted to User - Java 不支持运行时自动向上转型;必须显式满足 IS-A 关系(继承/实现)
- 子类构造器中调用
super(...)是确保父类字段可被多态访问的前提,否则可能空指针
泛型擦除后,void handle(List<string> list)</string> 还能接收 ArrayList 吗?
能。泛型只在编译期校验,运行时形参就是 List,所有实现类(ArrayList、LinkedList、自定义 MyList)都能传入。
性能 / 兼容性影响:
– 擦除后无额外开销,和直接写 List 一样快
– 但无法在运行时判断实际类型,所以不能靠 list.getClass() == ArrayList.class 做分支逻辑
- 如果需要区分实现类行为,应在接口中定义方法(如
list.optimizeForRandomAccess()),而不是在方法内if (list instanceof ArrayList) - 泛型形参
<t extends comparable>></t>是为了编译期约束,不改变多态传递能力 - 不要把
ArrayList<string></string>当作形参类型——这会锁死实现,违背多态初衷
Spring 中 @RequestBody User user 怎么让 JSON 自动映射成正确子类?
默认不行。Spring MVC 默认只认形参声明的类型(User),不会根据 JSON 字段猜子类。必须显式告诉 Jackson 如何识别。
常见错误现象:
– JSON 里有 "type": "admin",但反序列化出来仍是 User 实例,子类特有字段为 null
– 报错 Cannot construct instance of User(因为 User 是抽象类或接口)
- 在接口或抽象类上加
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type") - 每个子类加
@JsonSubTypes.Type(value = Admin.class, name = "admin") - 确保 JSON 包含对应 type 字段,且值匹配 name 值,否则 fallback 到默认类型或报错
最常被忽略的是子类字段的 getter/setter 缺失,或者用了 Lombok 但没加 @Data 或 @Setter,导致反序列化失败却不报明显错误。










