Java继承实现代码复用并支撑多态,子类可直接访问父类public/protected成员,但private成员不可见;需满足“is-a”关系,否则优先用组合;final类/方法限制继承与重写,过度继承增加维护成本。

继承让子类直接获得父类的非私有成员
Java 中的继承最直接解决的是代码复用问题:避免在多个类中重复写相同的字段和方法。只要父类中定义了 public 或 protected 的字段、方法,子类通过 extends 就能直接访问或调用,无需重写。
常见错误是误以为 private 成员也能被继承——它们虽参与父类对象构建,但子类中不可见、不可直接访问,只能通过父类提供的 public/protected 方法间接操作。
- 子类构造器默认第一行会隐式调用
super(),若父类无无参构造器,必须显式写super(...) -
final类不能被继承,final方法不能被重写,这是设计上对复用边界的控制 - 继承关系应满足“is-a”语义(如
Dogis aAnimal),强行继承会导致后期维护困难
继承支撑了多态与运行时行为替换
继承本身不等于多态,但它为多态提供了基础结构:只有存在父子类关系,才能用父类引用指向子类对象,进而实现方法重写(@Override)后的动态分派。
典型场景是统一处理不同子类型:List 里存 Dog 和 Cat,调用 makeSound() 时自动执行各自重写的版本。没有继承,这种抽象就无法落地。
立即学习“Java免费学习笔记(深入)”;
- 重写方法签名(名称、参数列表、返回类型协变)必须严格匹配父类声明
- 静态方法不能被重写,只能被隐藏;调用哪个版本取决于引用变量的编译时类型,而非实际对象类型
- 构造器中调用可重写方法是危险操作,此时子类字段尚未初始化,容易引发空指针或逻辑错乱
继承不是万能的,替代方案更灵活
当两个类之间不存在天然的“is-a”关系,却想复用代码时,硬套继承反而破坏设计。比如 “Car 有 Engine”,不是 “Car is an Engine”,这时应该用组合(has-a)。
组合配合接口(如 Runnable、Comparable)往往比继承更松耦合、更易测试、更利于扩展。Java 8+ 接口支持默认方法,进一步削弱了为复用而继承的必要性。
- 优先考虑组合:把共用逻辑封装进独立类,由多个业务类持有其引用
- 接口用于定义能力契约,抽象类适合提供部分实现 + 强制子类实现某些方法
- 过度继承(如三层以上)会让调用链变长、调试困难,JVM 也需更多时间解析虚方法表
继承带来的隐性成本常被低估
每次使用 extends,不只是加了一行代码,还绑定了子类与父类的生命周期:父类任何非 private 成员变更(如字段改名、方法加参数、抛新异常),都可能悄无声息地破坏子类编译或运行行为。
尤其在依赖第三方库时,继承其公开类等于把它的内部演化风险引入自己的代码。这也是为什么 Spring、Guava 等主流框架大量使用 final 类 + 工厂/构建器 + 接口回调,而非鼓励用户继承。
- 子类无法控制父类构造器逻辑,也无法绕过它执行自己的初始化
- 序列化时若父类未实现
Serializable,子类即使实现了也会抛NotSerializableException - 反射获取继承链上的方法时,
getDeclaredMethods()不包含父类方法,需手动遍历getSuperclass()








