继承 (Inheritance) — AP Computer Science A CS A 学习指南
适合谁:AP Computer Science A 参加 AP Computer Science A 的考生。
覆盖内容:超类与子类定义、extends与super关键字用法、方法重写与@Override注解规则、多态IS-A关系、抽象类入门核心考点
前置知识:基础 Java 或任何其他过程式语言编程。
关于练习题:下文「练习题」一节的所有题目均为我们按 AP Computer Science A 风格编写的原创题目 (original problems),仅用于教学。它们不是 College Board 真题的复制,措辞、数值或语境可能不同。请把它们当作练手用;评分细则请对照 College Board 官方 mark scheme。
1. 什么是继承?
继承(Inheritance)是面向对象编程中实现代码复用的核心机制,允许新建的类吸收已有类的属性、方法,同时扩展自定义的功能,避免重复编写相同逻辑。本章节对应AP CS A CED第9单元,占考试总分约8%-10%,选择题和自由作答(FRQ)均会出题,是面向对象模块的核心考点。 继承的核心价值是实现类的层次化设计,符合现实世界的分类逻辑,比如「学生是人的一种」「狗是动物的一种」,无需在每个细分分类中重复定义通用属性。
2. 超类(Superclass)与子类(Subclass)
被继承的类称为超类(Superclass,也叫父类),继承超类的新类称为子类(Subclass,也叫派生类)。
子类可以直接访问超类的public、protected成员(属性、方法),但无法直接访问超类的private成员,必须通过超类提供的公开方法间接访问。
范例
// 超类:定义通用属性和方法
public class Person {
private String name;
private int age;
public Person(String n, int a) { name = n; age = a; }
public void greet() { System.out.println("你好,我是" + name); }
}
// 子类:继承Person,扩展独有属性studentId和方法study
public class Student extends Person {
private String studentId;
public void study() { System.out.println("正在学习AP CS A"); }
}
上述代码中Student IS-A Person,自动拥有greet()方法,无需重复编写。
3. extends关键字与super调用
extends是Java中声明继承关系的关键字,语法为class 子类名 extends 超类名。注意Java仅支持单继承,一个子类最多只能继承一个超类,这是AP选择题的高频考点。
super关键字有两个核心用法:
- 调用超类构造方法:必须放在子类构造方法的第一行。如果子类构造没有显式写
super调用,编译器会自动添加无参的super();如果超类没有无参构造方法,会直接编译报错。 - 调用超类的普通成员:当子类重写了超类方法后,可以用
super.方法名()调用超类的原实现,也可以用super.属性名访问超类的非私有属性。
范例
public class Student extends Person {
private String studentId;
public Student(String n, int a, String id) {
super(n, a); // 第一行调用超类有参构造,初始化name和age
studentId = id;
}
@Override
public void greet() {
super.greet(); // 调用超类的greet实现
System.out.println("我的学号是" + studentId);
}
}
4. 方法重写(Method Overriding)与@Override
方法重写指子类定义和超类方法签名完全相同(方法名、参数列表、返回值类型一致)的方法,覆盖超类的原有实现,是实现多态的前提。
@Override是Java提供的注解,加在重写方法上方后,编译器会自动检查该方法是否符合重写规则,如果拼写错误、参数列表不匹配会直接报错,避免逻辑bug,AP考试中建议所有重写方法都添加该注解。
重写的核心规则:
- 访问修饰符不能比超类方法更严格(比如超类是
public,子类不能用protected) - 不能抛出比超类方法更宽泛的受检异常
⚠️ 注意和方法重载(Overload)区分:重载是同一个类中方法名相同、参数列表不同,和重写没有关系,不能加
@Override注解,这是高频丢分点。
5. 多态(Polymorphism)与IS-A关系
继承天然存在IS-A关系,比如Student IS-A Person,多态就是基于IS-A关系实现的特性:超类类型的引用可以指向子类类型的对象,调用同一个方法时,实际执行的逻辑取决于引用指向的实际对象类型,这个机制叫做动态绑定(Dynamic Binding),是AP必考考点。
范例
Person p1 = new Person("张三", 18);
Person p2 = new Student("李四", 17, "2024001");
p1.greet(); // 执行Person类的greet方法
p2.greet(); // 执行Student类重写后的greet方法
⚠️ 注意:编译阶段只会检查引用的编译类型(上述例子中是Person)有没有对应方法,要调用子类独有的方法(比如study()),必须先强制类型转换为子类类型:((Student)p2).study();
6. 抽象类(Abstract Classes)入门
抽象类是用abstract关键字修饰的类,核心规则如下:
- 不能被实例化(不能用
new直接创建抽象类的对象) - 可以包含抽象方法:用
abstract修饰、只有方法签名没有实现的方法,比如public abstract double getArea(); - 继承抽象类的非抽象子类,必须实现抽象类中所有的抽象方法,否则该子类也要声明为抽象类
- 抽象类也可以包含普通实现的方法、属性、构造方法,并非只能有抽象方法 抽象类通常用来定义类层次的通用模板,把公共逻辑写在抽象类中,把需要子类个性化实现的逻辑定义为抽象方法,强制子类实现。
7. 常见陷阱(Common Pitfalls)
- 错误做法:超类只有有参构造方法,子类构造没有显式调用
super(参数),导致编译报错。 原因:误以为编译器会自动匹配参数调用超类有参构造,实际默认只会加无参super()。 正确做法:如果超类没有无参构造,子类构造第一行必须显式调用super(参数)匹配超类的有参构造。 - 错误做法:把方法重载当成重写,添加
@Override后编译报错。 原因:分不清重写要求方法签名完全相同,重载仅要求方法名相同、参数不同。 正确做法:只有方法名、参数列表、返回值都和超类完全一致时才是重写,才能加@Override。 - 错误做法:超类引用指向子类对象时,直接调用子类独有的方法,编译报错。 原因:以为运行类型是子类就能调用子类所有方法,实际编译阶段只检查引用的编译类型。 正确做法:调用子类独有方法前先做强制类型转换,确保类型匹配。
- 错误做法:重写方法时使用比超类更严格的访问修饰符,比如超类是
public,子类写成protected。 原因:不知道重写的访问权限规则,重写是为了替代超类方法,不能缩小可访问范围。 正确做法:重写方法的访问修饰符必须和超类相同或更宽松(public>protected> 包访问 >private)。
8. 练习题(AP CS A风格)
题1(选择题)
现有代码如下:
class Animal {
public void makeSound() { System.out.print("普通叫声"); }
}
class Cat extends Animal {
@Override
public void makeSound() { System.out.print("喵"); }
public void scratch() { System.out.print("挠沙发"); }
}
执行代码Animal a = new Cat(); a.makeSound();的输出结果是?
A. 普通叫声 B. 喵 C. 编译错误 D. 运行异常
解答:选B。动态绑定机制下,方法调用看实际运行类型是Cat,执行重写后的makeSound方法。如果调用a.scratch()会编译错误,因为Animal类没有scratch方法。
题2(改错题)
下列代码有几处编译错误?请说明原因。
abstract class Shape {
private String color;
public Shape(String c) { color = c; }
public abstract double getArea();
}
class Circle extends Shape {
private double radius;
public Circle(String c, double r) { radius = r; }
public double getArea() { return Math.PI * radius * radius; }
}
解答:1处错误。Circle的构造方法没有显式调用超类Shape的有参构造,超类没有无参构造,编译器自动添加的super()无法匹配,应该在构造第一行添加super(c);。
题3(FRQ风格代码题)
请编写一个子类Square继承上述Shape抽象类,包含私有属性side(边长),构造方法接收颜色和边长两个参数,实现getArea方法返回正方形面积。
解答:
public class Square extends Shape {
private double side;
public Square(String color, double side) {
super(color);
this.side = side;
}
@Override
public double getArea() {
return side * side;
}
}
9. 速查表(Quick Reference Cheatsheet)
| 知识点 | 核心规则 |
|---|---|
extends关键字 |
Java单继承,一个子类最多继承一个超类 |
super构造调用 |
必须放在子类构造第一行,无显式调用时编译器自动加无参super() |
| 方法重写 | 方法签名完全相同,访问权限不低于超类,建议加@Override注解 |
| 动态绑定 | 方法调用看运行时实际对象类型,属性访问看编译时引用类型 |
| 抽象类 | abstract修饰,不能实例化,非抽象子类必须实现所有抽象方法 |
10. 接下来怎么学
继承是AP CS A面向对象模块的核心基础,后续要学习的接口(Interface)、多态进阶、类层次设计考点都建立在本章的IS-A关系、方法重写、动态绑定规则之上,本章知识点在FRQ中常和数组、ArrayList结合出题,需要你熟练掌握规则并灵活应用。
如果你在做继承相关真题时遇到任何疑问,都可以随时到小欧提问,我们会给你提供针对性的讲解和练习巩固。