掌握Java面向对象需理清继承、多态与抽象类的依赖关系:继承是基础,多态是满足继承+重写+向上转型三条件的结果,抽象类是定义模板与强制契约的设计工具,三者职责分明,不可混淆。

掌握Java面向对象中继承、多态与抽象类,关键不在背概念,而在理清三者之间的依赖关系和运行时行为。继承是基础,多态是结果,抽象类是设计工具——踩坑往往发生在混淆它们的职责或忽略底层约束。
继承:别把“能用”当成“能访问”
子类继承父类,不等于能直接使用父类所有成员。真正决定能否访问的,是访问修饰符+包结构+继承链位置:
- private字段和方法完全不可见,子类不能调用也不能重写,只能通过父类提供的public/protected getter/setter间接操作
- 默认(包级)成员只在同包内有效,跨包子类哪怕用了extends,也访问不到这些成员
- protected是为继承而生的修饰符:同包可访问,不同包子类也可访问,但不同包普通类不行——这是设计父类API时最常用的权限
- super()必须放在子类构造器第一行,否则编译失败;如果父类没有无参构造器,子类必须显式调用super(…)传参
多态:不是“写了就能用”,而是“满足条件才生效”
多态不是语法糖,它依赖三个硬性条件同时成立:
- 有继承或实现关系(如A extends B,或C implements D)
- 有方法重写(子类重写了父类的非static、非private、非final方法)
- 有向上转型(父类引用指向子类对象,如Animal a = new Cat();)
只要缺一个,就只是普通调用,不是多态。常见误区:把重载(overload)当成重写(override),或者在静态方法、私有方法上加@Override——编译器不会报错,但运行时根本不会触发多态。
立即学习“Java免费学习笔记(深入)”;
抽象类:不是“没写完的类”,而是“强制规范的契约”
抽象类的核心价值是定义模板+约束实现,不是为了省代码。避坑重点:
- 抽象方法必须被非抽象子类重写,否则子类也得声明为abstract;接口中的default方法可不重写,但抽象类里没有这种“可选”机制
- 抽象类可以有构造器,虽然不能new,但子类构造时会隐式或显式调用它,用于初始化共用状态
- 抽象类中允许存在具体方法、静态方法、甚至main方法,这些都能被子类继承并直接调用,不必重写
- 抽象类和接口不是二选一,而是分层协作:抽象类定义“是什么”(is-a),接口定义“能做什么”(can-do),比如Animal是抽象类,Flyable是接口,Bird extends Animal implements Flyable
组合陷阱:别用继承替代组合
当两个类之间不是“is-a”,而是“has-a”或“uses-a”关系时,强行继承会导致语义混乱和维护灾难:
- 比如“汽车有引擎”,不是“汽车是一种引擎”,该用组合(Car持有Engine引用),而不是让Car extends Engine
- 继承暴露父类细节,组合隐藏实现;继承破坏封装性,组合更灵活、更易测试
- JDK自身大量使用组合:ArrayList内部用Object[]数组,HashMap用Node[]数组,都没让它们继承数组类
不复杂但容易忽略。真正写好面向对象,不是堆砌关键字,而是每次写extends、abstract或@Override时,都问一句:这个设计是否符合现实关系?是否留出了扩展空间?是否让调用方更简单而不是更困惑?


















