Java 继承、方法重写与 final
继承让类与类产生父子关系,子类免费获得父类的非私有成员,Java 由此搭起整个类体系。本篇讲清 extends 的 is-a 语义、继承的成员规则、构造方法的”先父后子”、方法重写的约束与 final 的三种用法,为多态铺路。
本篇目标
- 能用 is-a 原则判断该不该用继承
- 掌握单继承、多层继承的规则与继承的利弊
- 说清子类构造为什么”先父后子”,会用 super
- 掌握方法重写的规则与 @Override 的作用
- 记住 final 修饰类、方法、变量的三种语义
为什么需要继承
先看痛点:分别定义 Cat 和 Dog,颜色、腿数、吃饭、睡觉各写一遍,改一个公共字段要动两个文件。把共性抽到 Animal 父类,让 Cat、Dog extends Animal,重复代码瞬间消失。继承的好处:提高复用性、提高维护性、让类与类产生关系——第三点是多态的前提。弊端同样明确:父类一变子类全受影响,耦合性增强。开发追求高内聚、低耦合,所以继承要用得克制,不能为了蹭部分功能而继承。
继承的规则:单继承与 is-a
Java 只支持单继承(一个类只能有一个直接父类),但支持多层继承(A extends B extends C),所有类的根都是 Object。用继承前先过一遍假设法:A 是 B 的一种才考虑继承——“学生是人””苹果是水果”成立;项目经理和程序员只差一个奖金属性,不该为此继承。看继承体系有个技巧:想用最全的功能就 new 最底层的类,想看共性就翻最顶层的类。
访问边界:子类能继承父类所有非私有成员(私有字段可通过继承来的 public get/set 间接访问);构造方法不能被继承,但子类构造里可以用 super(…) 调用父类构造。
继承中的成员变量与 super
子父类变量不同名时各用各的;同名时,子类中直接写名字访问到的是子类的(就近原则),想访问父类同名变量用 super.变量名。this 与 super 的分工:this 是当前对象的引用,先找本类、本类没有再找父类;super 是当前对象里父类部分的引用,只找父类。调构造时 this(...) 调本类其他构造,super(...) 调父类构造。
构造方法调用链:先父后子
子类的每个构造方法,第一行都默认有一句隐式的 super()。原因:子类继承了父类的数据并可能使用它,所以子类初始化前必须先完成父类部分的初始化。于是 new Zi() 时先执行父类构造、再执行子类构造,这条链一路向上直到 Object。
注意事项:父类若没有无参构造,隐式 super() 编译失败,必须显式写 super(参数) 匹配父类已有构造;或者用 this(…) 拐到本类另一个构造(最终仍会触达父类构造)。super(…) 和 this(…) 都必须放在构造方法第一行,因此二者不能同时出现。记住执行顺序面试题:父静态代码块 → 子静态代码块 → 父构造代码块 → 父构造 → 子构造代码块 → 子构造。
方法重写:子类对父类的定制
子类需要父类的功能签名、但实现细节有自己的内容时,重写(Override)父类方法:方法名、参数列表完全一致,返回值类型相同或是其子类。典型例子:手机类有 call(),智能手机继承后把 call() 重写成”视频通话”——沿用父类功能,替换子类实现。
重写军规:父类私有方法不能被重写(子类根本继承不到);子类重写时访问权限不能比父类更低,建议保持一致;父类静态方法只能被子类静态方法”隐藏”,不算重写(静态属于类,不参与多态);最好声明写得一模一样。重写与重载别混淆:重载在同一类内、只看参数列表、与返回值无关;重写在子父类之间、声明必须一致。子类对象调方法时先找子类本身,再找父类。
实践中永远给重写方法加 @Override:它不参与运行,但让编译器把关——方法名拼错、参数写错时立刻报错,而不是悄悄变成一个新方法。
final 的三种用法
final 是”最终”:修饰类,类不能被继承(String 就是 final,防止核心类行为被篡改);修饰方法,方法不能被重写;修饰变量,变量变常量,只能赋值一次。引用类型的细节:final 锁的是地址,不是对象内容——final 数组不能再指向别的数组,但元素可以改。final 成员变量的初始化时机二选一:定义时显式赋值,或保证在对象构造完毕前赋值。常量命名约定全大写加下划线:public static final int MAX_AGE = 130;。
经典练习:猫狗继承版
需求:动物有颜色和腿数,会吃饭;猫会抓老鼠,狗会看家。分析:颜色、腿数、eat() 抽到 Animal;catchMouse() 留给 Cat,lookHome() 留给 Dog;测试类分别 new 出两种动物,验证继承来的方法与特有方法都可用。写完再给 Cat 重写 eat() 输出”猫吃鱼”,体会”沿用签名、替换实现”。
小结
- 继承用 is-a 判断:单继承、可多层,根是 Object;好处是复用与维护,代价是耦合。
- 子类构造默认第一行 super(),父类部分先初始化;父类没有无参构造时必须显式 super(…)。
- 重写要求声明一致、权限不降低、私有方法不可重写;加 @Override 让编译器把关。
- final:类不可继承、方法不可重写、变量只能赋值一次(引用类型锁地址不锁内容)。
- 继承让父类引用可以指向子类对象——下一篇的多态正是从这里长出来的。

