第 17 章:继承
学习目标
- 理解继承的本质:代码复用 + 多态基础
- 掌握 extends 关键字和 super 用法
- 学会方法重写(Override)
- 理解构造器链
一、什么是继承?
继承是子类复用父类字段和方法的机制。
java
// 父类(基类)
public class Animal {
public String name;
public int age;
public void eat() {
System.out.println(name + " 在吃东西");
}
public void sleep() {
System.out.println(name + " 在睡觉");
}
}
// 子类(派生类)
public class Dog extends Animal { // ① 用 extends 关键字
public String breed; // ② 子类新增字段
public void bark() { // ③ 子类新增方法
System.out.println(name + " 在汪汪叫");
}
}
Dog dog = new Dog();
dog.name = "旺财";
dog.age = 3;
dog.breed = "柴犬";
dog.eat(); // 来自父类
dog.sleep(); // 来自父类
dog.bark(); // 来自子类二、继承的内存模型
子类对象包含父类的所有字段和方法,加上自己新增的部分。
三、方法重写(Override)
子类可以重写父类的方法,实现自己的行为:
java
public class Animal {
public void makeSound() {
System.out.println("动物发出声音");
}
}
public class Dog extends Animal {
@Override // ① 注解,编译器检查
public void makeSound() {
System.out.println("汪汪汪");
}
}
public class Cat extends Animal {
@Override
public void makeSound() {
System.out.println("喵喵喵");
}
}重写规则
| 维度 | 规则 |
|---|---|
| 方法签名 | 必须相同 |
| 返回类型 | 相同或协变(子类返回类型) |
| 访问修饰符 | 不能更严格 |
| 异常 | 不能抛出更宽泛的检查异常 |
java
// ❌ 错误:方法签名不同(不是重写,是重载)
public void makeSound(String sound) { }
// ❌ 错误:访问修饰符更严格
@Override
private void makeSound() { }
// ✅ 正确
@Override
public void makeSound() { }四、super 关键字
4.1 调用父类方法
java
public class Dog extends Animal {
@Override
public void makeSound() {
super.makeSound(); // ① 调用父类方法
System.out.println("汪汪汪");
}
}4.2 调用父类构造器
java
public class Animal {
public String name;
public Animal(String name) {
this.name = name;
}
}
public class Dog extends Animal {
public String breed;
public Dog(String name, String breed) {
super(name); // ① 必须放在第一行
this.breed = breed;
}
}4.3 访问父类字段
java
public class Dog extends Animal {
@Override
public void printInfo() {
System.out.println("name: " + super.name); // 父类的 name
}
}五、构造器链
子类构造器必须先调用父类构造器:
java
public class Animal {
public Animal() {
System.out.println("Animal 无参构造器");
}
}
public class Dog extends Animal {
public Dog() {
super(); // ① 编译器自动添加(可以不写)
System.out.println("Dog 无参构造器");
}
}
// 输出:
// Animal 无参构造器
// Dog 无参构造器六、继承的限制
6.1 单继承
Java 只支持单继承(一个类只能有一个直接父类):
java
// ❌ 编译报错
public class Dog extends Animal, Pet { }
// ✅ 多层继承
public class A { }
public class B extends A { }
public class C extends B { } // C 间接继承 A需要"多继承"效果时,用接口(第 21 章)或组合。
6.2 访问父类的私有字段
java
public class Animal {
private String secret = "秘密"; // private
}
public class Dog extends Animal {
public void test() {
System.out.println(secret); // ❌ 编译报错:不可见
System.out.println(super.secret); // ❌ 也不行
}
}父类的
private字段,子类不能直接访问,需要通过protected或 getter/setter。
6.3 final 类不可继承
java
public final class String { ... } // ❌ 不能 extends String
String、Math等都是 final 类。
七、什么时候用继承?
| 关系 | 推荐 |
|---|---|
| Dog is Animal | 继承 |
| Car has Engine | 组合(has-a) |
| Bird can Fly | 接口(can-do) |
企业级原则:优先用组合而非继承(Effective Java Item 18)。
八、完整代码示例
java
/**
* 继承综合示例
*
* 配套文档:第 17 章 继承
*/
// ============ 父类 ============
class Animal {
protected String name; // protected:子类可访问
protected int age;
public Animal(String name, int age) {
this.name = name;
this.age = age;
System.out.println("Animal 构造器: " + name);
}
public void eat() {
System.out.println(name + " 在吃东西");
}
public void makeSound() {
System.out.println(name + " 发出声音");
}
}
// ============ 子类 ============
class Dog extends Animal {
private String breed;
public Dog(String name, int age, String breed) {
super(name, age); // 调用父类构造器
this.breed = breed;
System.out.println("Dog 构造器: " + breed);
}
@Override // 重写父类方法
public void makeSound() {
super.makeSound(); // 调用父类
System.out.println(name + " 汪汪叫");
}
public void fetch() { // 子类新增方法
System.out.println(name + " 在捡球");
}
}
// ============ 测试 ============
public class InheritanceDemo {
public static void main(String[] args) {
Dog dog = new Dog("旺财", 3, "柴犬");
// 来自父类的方法
dog.eat(); // 旺财 在吃东西
// 重写后的方法
dog.makeSound(); // 旺财 发出声音\n旺财 汪汪叫
// 子类自己的方法
dog.fetch(); // 旺财 在捡球
// 访问父类 protected 字段
System.out.println("名字: " + dog.name);
System.out.println("年龄: " + dog.age);
System.out.println("品种: " + dog.breed);
}
}输出:
Animal 构造器: 旺财
Dog 构造器: 柴犬
旺财 在吃东西
旺财 发出声音
旺财 汪汪叫
旺财 在捡球
名字: 旺财
年龄: 3
品种: 柴犬九、本章小结
| 要点 | 关键 |
|---|---|
| 继承本质 | 子类复用父类字段和方法 |
| extends | 单继承,子类只能有一个直接父类 |
| 方法重写 | 子类重新实现父类方法,加 @Override 注解 |
| super | 调用父类方法 / 构造器 / 字段 |
| 构造器链 | 子类构造器必须先调用父类构造器 |
| 继承 vs 组合 | is-a 用继承,has-a 用组合 |
动手练习
练习 1:基础题
设计 Employee → Manager 继承关系:
java
Employee: name, salary, work()
Manager: bonus, manage()(重写 work())练习 2:进阶题
实现一个图形继承体系:
java
Shape (abstract): area(), perimeter()
├── Circle (radius)
├── Rectangle (width, height)
└── Triangle (a, b, c)下一章:第 18 章:多态 →