模块课程(2/2)
多态性和抽象类
多态性和抽象类是高级的面向对象编程概念,使我们能够编写独立于具体实现的灵活、可扩展的代码。
多态性
术语“多态性”(多种形式)是指将不同类的对象视为属于同一类型的能力。在Java中,超类引用变量可以存储对其任何子类的对象的引用。
class Animal {
public void makeSound() {
System.out.println("Verso...");
}
}
class Dog extends Animal {
public void makeSound() {
System.out.println("Woof");
}
}
class Cat extends Animal {
public void makeSound() {
System.out.println("Miao");
}
}由于多态性,我们可以这样做:
Animal myAnimal1 = new Dog(); // Polymorphism
Animal myAnimal2 = new Cat(); // Polymorphism
myAnimal1.makeSound(); // Executes Dog's method (Woof)
myAnimal2.makeSound(); // Executes Cat's method (Miao)调用哪个方法的决定是在运行时(后期绑定或动态分派)根据实际对象而不是引用变量的类型做出的。
抽象类 (abstract)
抽象类是用 abstract 关键字标记的类,不能直接实例化(不能执行 new MyAbstractClass())。它充当其他类的“部分模板”。
抽象方法
抽象类可以包含抽象方法:声明的方法没有主体(没有花括号,没有代码),以分号结尾。非抽象子类需要实现所有继承的抽象方法。
abstract class Shape {
String color;
// Abstract method (no body)
public abstract double getArea();
}
class Circle extends Shape {
double radius;
public Circle(double radius) {
this.radius = radius;
}
// Required to implement getArea
@Override
public double getArea() {
return Math.PI * radius * radius;
}
}动态绑定/后期绑定
Java如何知道运行时要执行哪个方法?此过程称为后期绑定(或动态绑定)。与重载(在编译时解决)不同,编译器不知道将执行哪个特定方法。相反,它生成通用调用指令。在运行时,Java 虚拟机 (JVM) 检查内存中的实际对象并调用该对象的类中定义的方法实现。
抽象类和缺失的实现
如果子类继承自抽象类,它有两种选择:
- 实现所有抽象方法:在这种情况下,子类可以是普通(具体)类,并且可以实例化。
- 声明自身为抽象:如果子类没有为所有继承的抽象方法提供实现,也必须使用
abstract关键字进行声明。
abstract class Animal {
public abstract void makeSound();
}
// This class MUST be abstract because it does not implement makeSound()
abstract class Canine extends Animal {
// Inherits makeSound() but does not implement it
}自己尝试一下
声明一个 Shape 类型的变量 s 并使用多态性为其分配一个新的 Circle 对象。
显示提示
编写“Shape s = new Circle();”以使用基本类型作为引用类型。
3 次尝试后可用的解决方案
使 Shape 类抽象并添加抽象方法 double getArea()。然后完成 Square,使其扩展 Shape 并实现 getArea() 返回 side * side。
显示提示
在 Shape 中声明 `public abstract double getArea();`。在 Square 中,添加 `@Override public double getArea() { return side * side; }`。
3 次尝试后可用的解决方案
在 main 方法中声明一个 Shape[] 类型的数组,其中包含一个半径为 2.0 的 Circle 对象和一个边长为 3.0 的 Square 对象。然后,使用循环(for 或 for-each)通过调用 getArea() 方法来打印每个形状的面积。
显示提示
使用“Shape[] Shapes = { new Circle(2.0), new Square(3.0) };”声明数组,并使用“for (Shape s : Shapes)”打印“s.getArea()”循环遍历它。
3 次尝试后可用的解决方案