java没有鸭子类型,靠接口和多态模拟:必须声明接口(如quackable)才能调用quack(),编译期检查类型而非运行时方法存在;接口适用于行为约定,抽象类适用于共享实现;滥用instanceof暴露设计缺陷。

Java 没有鸭子类型,这是常见误解的源头。它靠接口和多态模拟类似效果,但机制完全不同——不是“看起来像就行”,而是“声明了就能用”。
为什么 duck.quack() 在 Java 里不能直接调用,除非有接口约束
Java 是静态类型语言,编译期就检查方法是否存在。哪怕两个类都有 quack() 方法,只要没共同接口或父类,就不能被同一段代码统一处理。
- 错误现象:
Object duck = new MallardDuck(); duck.quack();编译失败 ——Object类没有quack() - 正确做法:定义
interface Quackable { void quack(); },让MallardDuck和DecoyDuck都implements Quackable - 关键点:不是看运行时对象“有没有这个方法”,而是看变量声明类型“能不能保证有这个方法”
Quackable 接口 vs 抽象类:什么时候该选哪个
选接口更常见,尤其当只是约定行为、不共享实现逻辑时。
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 用接口:
Quackable、Flyable、Swimmable—— 多个无关类(鸭子、机器人鸭、橡皮鸭)可自由组合实现 - 用抽象类:当需要共享字段或默认行为,比如
AbstractDuck提供name字段和display()默认实现 - 注意:Java 不支持多继承,但一个类可实现多个接口 —— 这是鸭子式灵活的关键支撑
多态调用时,instanceof 和类型强转为什么常是坏信号
频繁用 instanceof 判断再强转,说明接口设计没覆盖真实需求,把本该由多态解决的问题推给了客户端代码。
- 反模式:
if (duck instanceof MallardDuck) { ((MallardDuck) duck).performFly(); } - 改进方向:在
Quackable上加performFly(),或拆出Flyable接口,让具体类选择实现 - 性能影响:
instanceof本身开销小,但逻辑分散导致维护成本飙升,且容易漏掉新类型
真正难的不是写对语法,而是判断哪些行为该抽成接口、哪些该留给具体类。接口一旦发布,修改成本远高于类内部调整——所以别急着定义 Quackable,先想清楚谁会用它、怎么用、未来可能加什么操作。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










