Java面向对象设计常见误区包括:把类当容器、继承当复用、方法当过程;应坚持封装、优先接口与组合、构造函数确保不可变性、避免过度抽象。
Java面向对象设计最常见的误区,不是语法写错,而是把“类”当容器、“继承”当复用、“方法”当过程——结果代码越来越难改、测试越来越难写、协作越来越痛苦。
很多新手看到一个业务实体(比如 Order),第一反应是定义一堆 public 字段 + 一堆静态工具方法,美其名曰“简洁”。这直接破坏封装,也让后续加校验、审计、序列化逻辑无从下手。
典型表现:
Order 类里全是 public String orderId;,外部直接读写OrderUtils 静态类,和 Order 毫无关系order.setAmount(-100) 居然能通过编译并运行正确做法:
private,提供有约束的 setAmount(BigDecimal amount)
Order 自身的方法,而非丢给工具类static
一看到“猫是动物”“狗是动物”,就急着建 Animal 父类,再让子类重写 makeSound()。问题在于:一旦出现“机器人狗”(会叫但不是生物)、“电子猫”(有 UI 但不会抓老鼠),继承树立刻崩塌。
更隐蔽的问题是:为了共享字段或方法,在无关类之间硬拉出一个“父类”,比如让 Report 和 Notification 都继承 BaseMessage,只因为它们都有 title 和 sendTime —— 这是典型的“继承泄露”。
建议优先考虑:
interface Soundable、interface Sendable)class RobotDog { private final Speaker speaker; })新手常把构造函数当成“初始化字段的普通方法”,随便加一堆可选参数、允许传 null、甚至在构造中调用可被重写的方法——这会导致对象创建失败、状态不一致、子类构造出错。
常见错误示例:
public class User {
private String name;
public User(String name) {
this.name = name;
init(); // ❌ 构造中调用非 final 方法,子类重写后可能访问未初始化字段
}
protected void init() { /* ...
*/ }
}安全做法:
final,配合全参构造或 Builder 模式保证构建后不可变null 参数,用 Objects.requireNonNull(name, "name must not be null") 明确契约刚学完策略模式,就给所有 if-else 套一层 StrategyFactory;刚了解模板方法,就把三个相似方法强行抽出一个抽象基类,哪怕它们未来根本不会扩展。
这类设计看似“规范”,实则带来三重成本:
判断是否需要抽象的朴素标准:
大多数时候,先写具体实现,等第二个相似场景出现时再提炼,比一开始就画好类图靠谱得多。