不能直接 public 字段,因缺乏校验和控制;应 private 字段 + 带逻辑的 getter/setter,如 setage() 中校验年龄范围;封装不完整(无 getter/setter)或校验缺失均导致形同虚设。

封装:为什么不能直接 public 一个字段?
因为直接暴露 name 或 age 字段,等于把数据库表裸奔在大街上——谁都能改、谁都能读,连“年龄不能是负数”这种基本校验都得靠调用方自觉。
真正安全的封装是:用 private 锁住字段 + 提供带逻辑的 setName() 和 setAge() 方法。比如 setAge(int age) 里加一句 if (age 150) throw new IllegalArgumentException();,错误就拦在入口,而不是等业务出 bug 后才排查。
- 常见错误:只加
private却不写getter/setter→ 外部完全无法访问,类变废砖 - 容易踩的坑:在
setter里直接赋值,没做空值或范围检查 → 表面封装了,实际形同虚设 - 真实场景:用户注册时
setPassword(String pwd)必须加密存储,绝不能原样保存
继承:extends 不是万能复用键
继承表达的是严格的 “is-a” 关系(比如 Dog is-a Animal),不是“能用就拿来”。滥用 extends 会导致子类被迫继承一堆无关行为,后期改一个父类方法,可能意外影响十几个子类。
更轻量、更安全的复用方式其实是组合:让 Dog 持有一个 Legs 对象,而不是继承它。Java 只支持单继承,这点硬性限制也倒逼你思考“到底该不该继承”。
立即学习“Java免费学习笔记(深入)”;
- 常见错误:为复用工具方法而让无关类继承(如
ReportService extends StringUtils)→ 违反语义,编译都过不了 - 关键细节:
super()必须是子类构造器第一行;没写的话,编译器会自动加super(),但若父类没无参构造器,就会报错Implicit super constructor is undefined - 性能影响:继承本身无开销,但深度继承链(>5 层)会让方法查找变慢,JVM 需要逐层向上找重写方法
多态:父类引用调用子类方法,为什么有时不生效?
多态生效的前提只有一个:运行时对象确实是子类实例。写成 Animal a = new Dog(); a.bark(); 是错的——bark() 是 Dog 特有方法,Animal 类里没有,编译直接失败。
正确姿势是:父类定义通用行为(如 makeSound()),子类各自重写。然后用 Animal a = new Dog(); a.makeSound(); → 此时才触发动态绑定,调到 Dog 的实现。
- 常见错误:重载(
overload)和重写(override)混淆 → 前者是编译期决定,后者才是多态核心 - 参数差异:
@Override方法签名必须严格一致(包括返回类型,Java 5+ 支持协变返回,但仍是子类类型) - 容易忽略:
static方法不能被重写,只能被隐藏;private方法也不能被重写,子类里同名方法只是新定义
抽象:接口和抽象类,到底选哪个?
接口(interface)适合定义“能做什么”,比如 Drawable、Runnable;抽象类(abstract class)适合定义“是什么 + 共享实现”,比如 Animal 可以提供默认的 breath() 实现,又强制子类实现 makeSound()。
Java 8+ 接口可以有 default 方法,但这不意味着它该替代抽象类——default 方法只能提供“可选能力”,不能持有状态(没字段),也不支持构造器逻辑。
- 使用场景:
Shape是抽象类(有面积公式共性 + 要求子类算面积),Resizable是接口(任意对象都可实现,不关心它是不是 Shape) - 兼容性注意:给已有接口加
default方法是二进制兼容的;但加抽象方法,所有实现类必须立刻更新,否则编译失败 - 真实坑点:接口中字段默认是
public static final,哪怕你写int MAX_SIZE = 100;,别人也能直接用MyInterface.MAX_SIZE—— 别当常量容器乱塞配置









