Java 继承
Java - 继承
Section titled “Java - 继承”继承(Inheritance)是 Java 面向对象编程(OOP)的一个基本支柱。它允许一个类(称为子类或派生类)继承另一个类(称为父类或基类)的字段和方法。
这种机制促进了代码重用(避免重复),并在类之间建立了一种层次关系,通常称为 “IS-A” 关系。
“IS-A” 关系(类继承)
Section titled ““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的子类。CarIS-AVehicle。它从Vehicle继承了brand、year、displayInfo()和startEngine()。Car添加了自己的字段(numberOfDoors)和方法(honk())。Car重写了startEngine()方法,提供了 Car 特有的实现。Bicycle也是 IS-AVehicle,并以不同的方式重写了startEngine()。- 子类使用
super(arguments)调用父类构造函数。 @Override注解表明了重写父类方法的意图,有助于编译器捕获错误(例如,方法签名中的拼写错误)。
instanceof 运算符
Section titled “instanceof 运算符”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 }}通过继承实现多态
Section titled “通过继承实现多态”继承实现了多态性。你可以使用父类引用变量来引用子类对象。当你在父类引用上调用一个被重写的方法时,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 类中未定义。继承与接口(implements 关键字)
Section titled “继承与接口(implements 关键字)”虽然一个类只能 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)。
“HAS-A” 关系(组合)
Section titled ““HAS-A” 关系(组合)”虽然继承代表了“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检查对象与类/接口之间的类型关系。