讲解
继承(inheritance)让一个新类基于已有类来定义:class Dog extends Animal,Dog 自动获得 Animal 的全部非私有成员,只需补充自己特有的部分。被继承的叫父类(超类),继承的叫子类。Java 只支持单继承——一个类只能 extends 一个父类,但继承可以成链(Dog extends Animal,Animal extends LivingThing),所有类的最终祖先是 Object。
子类构造对象时,会先执行父类的构造方法再执行自己的:父类部分先就绪,子类部分才能搭建。用 super(参数) 显式调用父类构造方法,且必须是子类构造方法的第一行;不写的话编译器自动插入无参 super()——如果父类没有无参构造方法,这一步就会编译报错。super 还能用来调用被子类覆盖前的父类方法:super.speak()。
子类可以重新定义父类已有的方法,这叫重写(override):方法名、参数列表完全相同,方法体换成子类自己的实现,习惯上加 @Override 注解让编译器帮忙校验(名字拼错、签名不符会立刻报错,不加也能工作,但强烈建议加)。重写和重载别混淆:重载是同一个类里参数不同的同名方法,重写是子类对父类方法的重新实现。父类里被 private 修饰的成员子类继承不到(存在但不可直接访问),被 final 修饰的方法不允许重写。
示例
Dog 继承 Animal:继承字段、调用父类构造、重写方法:
class Animal {
protected String name;
public Animal(String name) {
this.name = name;
}
public void speak() {
System.out.println(name + " 发出声音");
}
}
class Dog extends Animal {
public Dog(String name) {
super(name);
}
@Override
public void speak() {
System.out.println(name + " 汪汪叫");
}
public void fetch() {
System.out.println(name + " 去捡球");
}
}
public class Main {
public static void main(String[] args) {
Dog dog = new Dog("旺财");
dog.speak();
dog.fetch();
Animal generic = new Animal("某动物");
generic.speak();
}
}
用 super 调用父类版本,在重写基础上扩展而不是完全替换:
class Employee {
protected String name;
protected double baseSalary;
public Employee(String name, double baseSalary) {
this.name = name;
this.baseSalary = baseSalary;
}
public double getPay() {
return baseSalary;
}
}
class Manager extends Employee {
private final double bonus;
public Manager(String name, double baseSalary, double bonus) {
super(name, baseSalary);
this.bonus = bonus;
}
@Override
public double getPay() {
return super.getPay() + bonus;
}
}
public class Main {
public static void main(String[] args) {
Employee e = new Employee("张三", 8000);
Manager m = new Manager("李四", 12000, 3000);
System.out.println(e.name + " 的薪资:" + e.getPay());
System.out.println(m.name + " 的薪资:" + m.getPay());
}
}
常见坑
- super(...) 不在第一行:调用父类构造方法必须是子类构造方法的第一条语句,放后面直接编译错误。
- 父类没有无参构造导致子类编译失败:父类一旦只提供带参构造,子类就必须显式写 super(参数)。给父类加构造方法时想想子类的处境。
- 重写时签名不一致变成「重载」:参数列表差一个类型,@Override 立刻帮你发现;不加注解的话程序能编译,但调用的永远是父类版本,bug 极难排查。重写必加 @Override。
- 把继承当万能复用:继承表达的是「是一种」(is-a)关系,Dog 是一种 Animal 才合理;为了复用几个方法就继承(比如「汽车继承方向盘」)会让类层次变成灾难。复用优先考虑「有一个」(组合)。
小结
extends 单继承,super 调父类构造与方法,@Override 校验重写;继承用于 is-a 关系,复用优先组合。下一节看继承真正的威力:多态。