一、多态的核心思想
-
“同一接口,不同实现”:父类引用可以指向子类对象,调用相同方法时根据实际对象类型执行不同的逻辑。
-
分类:
-
编译时多态(静态多态):方法重载(Overload)。
-
运行时多态(动态多态):方法重写(Override) + 向上转型(Upcasting)。
-
二、编译时多态:方法重载(Overload)
规则:
-
在同一个类中定义多个同名方法。
-
参数列表必须不同(类型、顺序、数量)。
-
与返回值类型无关。
public class Calculator {
// 方法1:两个int相加
public int add(int a, int b) {
return a + b;
}
// 方法2:三个int相加(参数数量不同)
public int add(int a, int b, int c) {
return a + b + c;
}
// 方法3:两个double相加(参数类型不同)
public double add(double a, double b) {
return a + b;
}
}
// 使用:
Calculator calc = new Calculator();
calc.add(2, 3); // 调用方法1
calc.add(1.5, 2.5); // 调用方法3
三、运行时多态:方法重写(Override)+ 向上转型
1. 方法重写(Override)
规则:
-
子类重写父类的方法,方法名、参数列表、返回值类型必须完全相同。
-
子类方法的访问权限不能比父类更严格(例如父类方法是
public
,子类不能改为private
)。
// 父类
class Animal {
public void makeSound() {
System.out.println("Animal makes a sound");
}
}
// 子类1
class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("Dog barks: Woof!");
}
}
// 子类2
class Cat extends Animal {
@Override
public void makeSound() {
System.out.println("Cat meows: Meow!");
}
}
2. 向上转型(Upcasting)
-
父类引用指向子类对象:
Animal myPet = new Dog();
-
通过父类引用调用被重写的方法时,实际执行的是子类的方法。
public class Main {
public static void main(String[] args) {
Animal animal1 = new Dog(); // 向上转型
Animal animal2 = new Cat();
animal1.makeSound(); // 输出 "Dog barks: Woof!"
animal2.makeSound(); // 输出 "Cat meows: Meow!"
}
}
四、多态的高级应用
1. 抽象类与多态
-
抽象类可以定义抽象方法(无实现),强制子类重写。
-
抽象类不能实例化,但可以通过多态指向子类对象。
abstract class Shape { public abstract double calculateArea(); // 抽象方法 } class Circle extends Shape { private double radius; public Circle(double radius) { this.radius = radius; } @Override public double calculateArea() { return Math.PI * radius * radius; } } class Square extends Shape { private double side; public Square(double side) { this.side = side; } @Override public double calculateArea() { return side * side; } } // 使用多态: Shape shape1 = new Circle(5); Shape shape2 = new Square(4); System.out.println(shape1.calculateArea()); // 输出圆的面积 System.out.println(shape2.calculateArea()); // 输出正方形的面积
2. 接口与多态
-
接口定义行为规范,类通过
implements
实现接口。 -
一个类可以实现多个接口,突破单继承限制。
interface Flyable {
void fly();
}
interface Swimmable {
void swim();
}
class Duck implements Flyable, Swimmable {
@Override
public void fly() {
System.out.println("Duck flies with wings");
}
@Override
public void swim() {
System.out.println("Duck swims in water");
}
}
// 使用接口多态:
Flyable flyingThing = new Duck();
flyingThing.fly(); // 调用Duck的fly方法
五、常见问题解答
-
为什么父类引用不能调用子类特有方法?
父类引用只能访问父类中定义的方法和属性,若需调用子类特有方法,需向下转型。 -
多态与方法重载的区别?
重载是编译时多态(静态),重写是运行时多态(动态)。 -
接口和抽象类如何选择?
-
接口:定义行为规范,支持多继承。
-
抽象类:提供部分实现,用于“is-a”关系。
-
六、练习建议
-
实现一个
Animal
父类,派生Bird
、Fish
子类,重写move()
方法。 -
使用接口定义
Playable
,让不同类实现play()
方法。 -
尝试通过多态实现一个简单的集合遍历(如
List
存储不同子类对象)。