Skip to content

Java 继承

继承(Inheritance)是 Java 面向对象编程(OOP)的一个基本支柱。它允许一个类(称为子类或派生类)继承另一个类(称为父类或基类)的字段和方法。

这种机制促进了代码重用(避免重复),并在类之间建立了一种层次关系,通常称为 “IS-A” 关系。

Java 中用于类继承的主要关键字是 extends。当类 B extends 类 A 时,意味着 B 是 A 类型的一种。子类 B 继承了父类 A 的所有非私有成员(字段和方法)。

示例层次结构:

// 父类
class Vehicle {
String brand;
int year;
public Vehicle(String brand, int year) {
this.brand = brand;
this.year = year;
}
void displayInfo() {
System.out.println("Brand: " + brand + ", Year: " + year);
}
void startEngine() {
System.out.println("Vehicle engine starting...");
}
}
// 从 Vehicle 继承的子类
class Car extends Vehicle {
int numberOfDoors;
public Car(String brand, int year, int doors) {
// 使用 super() 调用父类构造函数
// 必须是子类构造函数中的第一个语句
super(brand, year);
this.numberOfDoors = doors;
}
// Car 特有的方法
void honk() {
System.out.println("Car horn: Beep beep!");
}
// 重写父类的方法
@Override // 推荐使用的注解
void startEngine() {
System.out.println("Car engine starting with a key turn...");
}
}
// 另一个子类
class Bicycle extends Vehicle { // 在这个模型中,自行车也可以视为 Vehicle
boolean hasBell;
public Bicycle(String brand, int year, boolean bell) {
super(brand, year);
this.hasBell = bell;
}
@Override
void startEngine() {
System.out.println("Bicycle doesn't have an engine!"); // 特有行为
}
void ringBell() {
if(hasBell) {
System.out.println("Bicycle bell: Ring ring!");
} else {
System.out.println("This bicycle has no bell.");
}
}
}

在这个示例中:

  • Vehicle 是父类。
  • Car 和 Bicycle 是 Vehicle 的子类。
  • Car IS-A Vehicle。它从 Vehicle 继承了 brand、year、displayInfo() 和 startEngine()。
  • Car 添加了自己的字段(numberOfDoors)和方法(honk())。
  • Car 重写了 startEngine() 方法,提供了 Car 特有的实现。
  • Bicycle 也是 IS-A Vehicle,并以不同的方式重写了 startEngine()。
  • 子类使用 super(arguments) 调用父类构造函数。
  • @Override 注解表明了重写父类方法的意图,有助于编译器捕获错误(例如,方法签名中的拼写错误)。

instanceof 运算符用于检查一个对象是否是某个特定类或该类的子类的实例。

public class InheritanceCheck {
public static void main(String[] args) {
Vehicle generalVehicle = new Vehicle("Generic", 2020);
Car myCar = new Car("Toyota", 2022, 4);
Bicycle myBike = new Bicycle("Giant", 2023, true);
System.out.println("myCar instanceof Car: " + (myCar instanceof Car)); // true
System.out.println("myCar instanceof Vehicle: " + (myCar instanceof Vehicle)); // true (IS-A 关系)
System.out.println("myBike instanceof Bicycle: " + (myBike instanceof Bicycle)); // true
System.out.println("myBike instanceof Vehicle: " + (myBike instanceof Vehicle)); // true (IS-A 关系)
System.out.println("generalVehicle instanceof Car: " + (generalVehicle instanceof Car)); // false
}
}

继承实现了多态性。你可以使用父类引用变量来引用子类对象。当你在父类引用上调用一个被重写的方法时,Java 会执行子类中该方法的版本(动态方法分派,dynamic method dispatch)。

// 继承检查示例的延续:
Vehicle vehicleRef1 = myCar; // Car 对象由 Vehicle 变量引用
Vehicle vehicleRef2 = myBike; // Bicycle 对象由 Vehicle 变量引用
vehicleRef1.startEngine(); // 调用 Car 重写的 startEngine() -> Car engine starting...
vehicleRef2.startEngine(); // 调用 Bicycle 重写的 startEngine() -> Bicycle doesn't have an engine!
vehicleRef1.displayInfo(); // 调用 Vehicle 的 displayInfo()(未重写)
// vehicleRef1.honk(); // 编译错误!honk() 在 Vehicle 类中未定义。

虽然一个类只能 extend(继承)一个父类(Java 支持单继承),但它可以 implement(实现)多个接口(interface)。

接口定义了一个契约——一组抽象方法(以及从 Java 8 开始可能包含的默认方法/静态方法),实现类必须提供这些方法的具体实现。

使用接口的示例:

interface Drivable {
void drive(); // 抽象方法(无方法体)
int MAX_SPEED = 120; // 常量隐式地为 public static final
}
interface Chargeable {
void charge();
}
// Car 现在继承 Vehicle 并实现 Drivable 接口
class ElectricCar extends Vehicle implements Drivable, Chargeable {
int batteryCapacity;
public ElectricCar(String brand, int year, int capacity) {
super(brand, year);
this.batteryCapacity = capacity;
}
@Override
public void drive() { // 必须实现 Drivable 接口中的 drive() 方法
System.out.println("Electric car is driving silently...");
}
@Override
public void charge() { // 必须实现 Chargeable 接口中的 charge() 方法
System.out.println("Plugging in the electric car to charge...");
}
@Override // 重写来自 Vehicle 的方法
void startEngine() {
System.out.println("Electric car motor starting up quietly...");
}
}
public class InterfaceCheck {
public static void main(String[] args) {
ElectricCar tesla = new ElectricCar("Tesla", 2023, 100);
System.out.println("tesla instanceof ElectricCar: " + (tesla instanceof ElectricCar)); // true
System.out.println("tesla instanceof Vehicle: " + (tesla instanceof Vehicle)); // true (via extends)
System.out.println("tesla instanceof Drivable: " + (tesla instanceof Drivable)); // true (via implements)
System.out.println("tesla instanceof Chargeable: " + (tesla instanceof Chargeable)); // true (via implements)
tesla.startEngine();
tesla.drive();
tesla.charge();
}
}

实现接口也建立了一种 IS-A 关系(例如,ElectricCar IS-A Drivable)。

虽然继承代表了“IS-A”关系,但有时你需要建模一种**“HAS-A”关系。这通过组合**(composition)来实现,即一个类包含另一个类的实例(一个字段)。

当关系并非严格的“IS-A”时,组合通常比继承更受青睐,因为它提供了更大的灵活性并避免了紧密耦合。

示例:一辆 Car HAS-A Engine

class Engine {
private String type;
private int horsepower;
public Engine(String type, int hp) {
this.type = type;
this.horsepower = hp;
}
public void start() {
System.out.println("Engine (" + type + ", " + horsepower + "hp) starting...");
}
public void stop() {
System.out.println("Engine stopping...");
}
}
// 使用组合的 Car 类(HAS-A Engine)
class CarWithEngine {
private String make;
private String model;
private Engine engine; // Car 拥有一个 Engine
public CarWithEngine(String make, String model, Engine engine) {
this.make = make;
this.model = model;
this.engine = engine; // 赋值 Engine 对象
}
public void startCar() {
System.out.println("Starting the " + make + " " + model + ".");
engine.start(); // 将启动操作委托给 Engine 对象
}
public void stopCar() {
System.out.println("Stopping the " + make + " " + model + ".");
engine.stop(); // 委托停止操作
}
// 如果需要,提供 Engine 的 getter
public Engine getEngine() {
return engine;
}
}
public class CompositionDemo {
public static void main(String[] args) {
Engine v6Engine = new Engine("V6", 300);
CarWithEngine mySedan = new CarWithEngine("Honda", "Accord", v6Engine);
mySedan.startCar();
mySedan.stopCar();
}
}

在这里,CarWithEngine 没有继承自 Engine。相反,它持有一个 Engine 对象的引用,并将与引擎相关的任务委托给它。这促进了代码重用(Engine 类可以在其他地方使用)和灵活性。

  • 继承(extends)建模了“IS-A”关系,促进了代码重用和多态性。
  • Java 支持单继承,但支持多接口实现(implements)。
  • 使用 super() 调用父类构造函数,使用 super.methodName() 调用父类方法。
  • 在打算重写父类方法时使用 @Override。
  • 组合(将另一个类的实例作为字段拥有)建模了“HAS-A”关系,并且通常因其灵活性而受到青睐。
  • instanceof 检查对象与类/接口之间的类型关系。