第一部分:继承基础概念
理解继承的本质和 Java 中的实现方式
学习目标
理解继承的意义,掌握 extends 关键字的使用,建立继承层次结构
1
什么是继承
继承是面向对象三大特性之一,允许一个类(子类)继承另一个类(父类)的属性和方法。
// 父类(基类、超类)
public class Vehicle {
protected String brand;
protected int year;
public Vehicle(String brand, int year) {
this.brand = brand;
this.year = year;
}
public void start() {
System.out.println(brand + " is starting...");
}
}
// 子类继承父类
public class Car extends Vehicle {
private int doors;
public Car(String brand, int year, int doors) {
super(brand, year); // 调用父类构造方法
this.doors = doors;
}
}
2
继承的内存结构
子类对象包含父类的所有成员变量和方法。
Vehicle 内存结构
brand: String
year: int
start(): void
Car 内存结构
↳ 继承 Vehicle 的所有成员
doors: int (新增)
第二部分:super 关键字详解
掌握 super 的 3 种核心用法
1
调用父类构造方法
使用 super() 调用父类构造方法,必须是子类构造方法的第一条语句。
public class Animal {
private String name;
public Animal(String name) {
this.name = name;
}
}
public class Dog extends Animal {
private String breed;
// 正确:super 必须是第一条语句
public Dog(String name, String breed) {
super(name); // 调用父类构造方法
this.breed = breed;
}
}
2
访问父类成员变量
当子类与父类有同名变量时,使用 super 明确访问父类变量。
public class Parent {
int value = 100;
}
public class Child extends Parent {
int value = 200;
public void printValues() {
System.out.println("Child value: " + value); // 200
System.out.println("Parent value: " + super.value); // 100
}
}
3
调用父类方法
在方法重写时,使用 super 调用父类的实现。
public class Vehicle {
public void start() {
System.out.println("Vehicle starting with basic engine");
}
}
public class ElectricCar extends Vehicle {
@Override
public void start() {
super.start(); // 先调用父类实现
System.out.println("Electric motor activated");
}
}
第三部分:方法重写与继承链
掌握 @Override 注解和多级继承
1
方法重写规则
- 方法名、参数列表必须相同
- 访问权限不能比父类更严格
- 返回类型可以是父类返回类型的子类型(协变返回类型)
- 抛出的异常不能比父类更多
public class Animal {
protected String getSound() {
return "generic animal sound";
}
}
public class Cat extends Animal {
@Override // 推荐添加此注解
public String getSound() { // 访问权限扩大
return "meow";
}
}
2
多级继承示例
class GrandParent {
void method1() { System.out.println("GrandParent method1"); }
}
class Parent extends GrandParent {
void method2() { System.out.println("Parent method2"); }
}
class Child extends Parent {
void method3() { System.out.println("Child method3"); }
}
// 使用示例
Child child = new Child();
child.method1(); // 继承自 GrandParent
child.method2(); // 继承自 Parent
child.method3(); // 自己的方法
第四部分:构造方法调用链
理解构造方法的自动调用机制
1
默认构造调用
如果子类构造方法没有显式调用 super(),编译器会自动插入 super()。
class A {
A() { System.out.println("A constructor"); }
}
class B extends A {
// 等价于:B() { super(); }
B() { System.out.println("B constructor"); }
}
// 输出顺序:A constructor → B constructor
2
带参数的构造调用
class Person {
String name;
Person(String name) {
this.name = name;
System.out.println("Person created: " + name);
}
}
class Employee extends Person {
double salary;
Employee(String name, double salary) {
super(name); // 必须第一行
this.salary = salary;
}
}
第五部分:常见错误与调试
总结继承中最容易犯的错误
错误1:super 不在首行
class Parent {
Parent(String name) {}
}
class Child extends Parent {
Child() {
int x = 10; // 错误:super 不是第一行
super("test");
}
}
super() 必须是构造方法中的第一条语句
错误2:私有成员不可继承
class Parent {
private int secret = 42;
}
class Child extends Parent {
void accessSecret() {
// System.out.println(secret); // 编译错误!
// 正确做法:通过公共方法访问
}
}
错误3:方法签名不匹配
class Parent {
public void test(int x) {}
}
class Child extends Parent {
// 这不是重写,而是重载!
public void test(String x) {}
}
第六部分:完整实战案例
通过银行系统演示继承的正确使用
1
基础类设计
// 基类:银行账户
public abstract class BankAccount {
private String accountNumber;
protected double balance;
public BankAccount(String accountNumber, double initialBalance) {
this.accountNumber = accountNumber;
this.balance = initialBalance;
}
public void deposit(double amount) {
balance += amount;
}
public abstract boolean withdraw(double amount);
public String getAccountInfo() {
return "Account: " + accountNumber + ", Balance: " + balance;
}
}
2
具体实现类
// 储蓄账户
public class SavingsAccount extends BankAccount {
private double interestRate;
public SavingsAccount(String accountNumber, double balance, double interestRate) {
super(accountNumber, balance); // 调用父类构造
this.interestRate = interestRate;
}
@Override
public boolean withdraw(double amount) {
if (amount <= balance) {
balance -= amount;
return true;
}
return false;
}
public void applyInterest() {
double interest = balance * interestRate / 100;
super.deposit(interest); // 使用父类方法
}
}
3
测试使用
public class BankTest {
public static void main(String[] args) {
SavingsAccount account = new SavingsAccount("SA001", 1000.0, 5.0);
System.out.println(account.getAccountInfo());
account.deposit(500);
account.applyInterest();
account.withdraw(200);
System.out.println(account.getAccountInfo());
}
}
第七部分:总结与最佳实践
继承使用的黄金法则
使用原则
- 使用继承表示"is-a"关系
- 子类应该能替代父类使用(里氏替换原则)
- 避免过深的继承层次(不超过3层)
- 优先使用组合而非继承
super 使用技巧
- 总是显式调用父类构造方法
- 使用 @Override 注解标记重写方法
- 在重写方法中先调用 super 保留父类行为
- 避免在构造方法中调用可重写的方法
综合练习
- 创建一个 Person → Employee → Manager 的继承层次
- 实现方法重写,展示多态行为
- 使用 super 调用父类构造和方法
- 添加异常处理和输入验证
学习建议
记住继承的核心是代码复用和多态。设计时先考虑"is-a"关系是否合理,再决定是否使用继承。调试时可以利用 IDE 的调试器逐步查看构造方法的调用顺序。