Java 多态(Polymorphism)
多态是面向对象编程的核心特性之一,它允许同一接口有不同的实现方式。理解多态是掌握面向对象编程的关键。本章将详细介绍 Java 中的多态机制。
多态的概念
什么是多态
**多态(Polymorphism)**是指同一接口可以有多种不同的实现方式。
核心思想:
- 同一接口:相同的方法调用
- 不同实现:不同的类提供不同的实现
- 运行时决定:根据实际对象类型调用对应的方法
多态的类型
Java 中的多态主要有两种形式:
- 编译时多态:方法重载(Overload)
- 运行时多态:方法重写(Override)
运行时多态(方法重写)
基本示例
// 父类
public class Animal {
public void makeSound() {
System.out.println("动物发出声音");
}
}
// 子类 1
public class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("汪汪汪");
}
}
// 子类 2
public class Cat extends Animal {
@Override
public void makeSound() {
System.out.println("喵喵喵");
}
}
// 多态使用
Animal animal1 = new Dog();
Animal animal2 = new Cat();
animal1.makeSound(); // 汪汪汪(调用 Dog 的方法)
animal2.makeSound(); // 喵喵喵(调用 Cat 的方法)
多态的工作原理
多态通过方法重写实现:
// 编译时:animal 的类型是 Animal
// 运行时:animal 指向的实际对象是 Dog
Animal animal = new Dog();
animal.makeSound(); // 运行时根据实际对象类型调用方法
过程:
- 编译时:检查
Animal类是否有makeSound()方法 - 运行时:根据实际对象类型(
Dog)调用对应的方法
多态的应用场景
1. 方法参数多态
方法参数使用父类类型,可以接收任何子类对象:
public class Animal {
public void eat() {
System.out.println("动物吃东西");
}
}
public class Dog extends Animal {
@Override
public void eat() {
System.out.println("狗吃骨头");
}
}
public class Cat extends Animal {
@Override
public void eat() {
System.out.println("猫吃鱼");
}
}
// 方法参数使用父类类型
public void feedAnimal(Animal animal) {
animal.eat(); // 多态:根据实际对象类型调用方法
}
// 使用
feedAnimal(new Dog()); // 狗吃骨头
feedAnimal(new Cat()); // 猫吃鱼
2. 数组多态
数组元素类型使用父类,可以存储任何子类对象:
Animal[] animals = new Animal[3];
animals[0] = new Dog();
animals[1] = new Cat();
animals[2] = new Animal();
// 统一处理
for (Animal animal : animals) {
animal.eat(); // 多态:根据实际对象类型调用方法
}
3. 集合多态
集合使用父类类型,可以存储任何子类对象:
List<Animal> animals = new ArrayList<>();
animals.add(new Dog());
animals.add(new Cat());
animals.add(new Animal());
// 统一处理
for (Animal animal : animals) {
animal.eat(); // 多态
}
4. 返回值多态
方法返回父类类型,可以返回任何子类对象:
public Animal createAnimal(String type) {
if ("dog".equals(type)) {
return new Dog();
} else if ("cat".equals(type)) {
return new Cat();
} else {
return new Animal();
}
}
// 使用
Animal animal = createAnimal("dog");
animal.eat(); // 多态
instanceof 运算符
类型检查
instanceof 用于检查对象是否是某个类的实例:
Animal animal = new Dog();
// 检查类型
if (animal instanceof Dog) {
System.out.println("是狗");
}
if (animal instanceof Animal) {
System.out.println("是动物");
}
// 类型转换
if (animal instanceof Dog) {
Dog dog = (Dog) animal; // 安全转换
dog.bark();
}
类型转换
向上转型(Upcasting):子类转父类,自动转换
Dog dog = new Dog();
Animal animal = dog; // 向上转型,自动转换
向下转型(Downcasting):父类转子类,需要强制转换
Animal animal = new Dog();
Dog dog = (Dog) animal; // 向下转型,需要强制转换
安全转换:
Animal animal = new Dog();
// ❌ 不安全:可能抛出 ClassCastException
// Cat cat = (Cat) animal;
// ✅ 安全:先检查类型
if (animal instanceof Dog) {
Dog dog = (Dog) animal;
dog.bark();
}
多态的优势
1. 代码复用
统一处理不同类型的对象:
// 不需要为每种类型写单独的方法
public void processAnimals(List<Animal> animals) {
for (Animal animal : animals) {
animal.eat(); // 统一处理
}
}
// 而不是
// public void processDogs(List<Dog> dogs) { }
// public void processCats(List<Cat> cats) { }
2. 可扩展性
添加新类型不需要修改现有代码:
// 现有代码
public void feedAnimal(Animal animal) {
animal.eat();
}
// 添加新类型
public class Bird extends Animal {
@Override
public void eat() {
System.out.println("鸟吃虫子");
}
}
// 不需要修改 feedAnimal 方法
feedAnimal(new Bird()); // 直接使用
3. 灵活性
运行时决定调用哪个方法:
Animal animal;
if (condition) {
animal = new Dog();
} else {
animal = new Cat();
}
animal.eat(); // 根据条件调用不同的方法
实际示例
示例 1:图形多态
// 父类:图形
public abstract class Shape {
protected String name;
public Shape(String name) {
this.name = name;
}
public abstract double getArea();
public void display() {
System.out.println("图形:" + name);
System.out.println("面积:" + getArea());
}
}
// 子类:圆形
public class Circle extends Shape {
private double radius;
public Circle(double radius) {
super("圆形");
this.radius = radius;
}
@Override
public double getArea() {
return Math.PI * radius * radius;
}
}
// 子类:矩形
public class Rectangle extends Shape {
private double width;
private double height;
public Rectangle(double width, double height) {
super("矩形");
this.width = width;
this.height = height;
}
@Override
public double getArea() {
return width * height;
}
}
// 多态使用
Shape[] shapes = {
new Circle(5),
new Rectangle(4, 6),
new Circle(3)
};
// 统一处理
for (Shape shape : shapes) {
shape.display(); // 多态:根据实际类型调用方法
}
示例 2:员工管理系统
// 父类:员工
public class Employee {
protected String name;
protected double baseSalary;
public Employee(String name, double baseSalary) {
this.name = name;
this.baseSalary = baseSalary;
}
public double calculateSalary() {
return baseSalary;
}
public void displayInfo() {
System.out.println("姓名:" + name);
System.out.println("薪资:" + calculateSalary());
}
}
// 子类:经理
public class Manager extends Employee {
private double bonus;
public Manager(String name, double baseSalary, double bonus) {
super(name, baseSalary);
this.bonus = bonus;
}
@Override
public double calculateSalary() {
return baseSalary + bonus;
}
}
// 子类:销售
public class Salesperson extends Employee {
private double commission;
private double sales;
public Salesperson(String name, double baseSalary, double commission, double sales) {
super(name, baseSalary);
this.commission = commission;
this.sales = sales;
}
@Override
public double calculateSalary() {
return baseSalary + sales * commission;
}
}
// 多态使用
List<Employee> employees = new ArrayList<>();
employees.add(new Employee("张三", 5000));
employees.add(new Manager("李四", 8000, 2000));
employees.add(new Salesperson("王五", 4000, 0.1, 50000));
// 统一计算薪资
for (Employee employee : employees) {
employee.displayInfo(); // 多态:根据实际类型计算薪资
}
示例 3:支付系统
// 接口:支付方式
public interface Payment {
void pay(double amount);
}
// 实现类:信用卡支付
public class CreditCardPayment implements Payment {
private String cardNumber;
public CreditCardPayment(String cardNumber) {
this.cardNumber = cardNumber;
}
@Override
public void pay(double amount) {
System.out.println("使用信用卡支付:" + amount);
}
}
// 实现类:支付宝支付
public class AlipayPayment implements Payment {
private String account;
public AlipayPayment(String account) {
this.account = account;
}
@Override
public void pay(double amount) {
System.out.println("使用支付宝支付:" + amount);
}
}
// 多态使用
Payment payment1 = new CreditCardPayment("1234-5678");
Payment payment2 = new AlipayPayment("alipay@example.com");
// 统一处理
Payment[] payments = {payment1, payment2};
for (Payment payment : payments) {
payment.pay(100.0); // 多态:根据实际类型调用方法
}
多态的注意事项
1. 只能调用父类中定义的方法
Animal animal = new Dog();
animal.makeSound(); // ✅ 可以调用(Animal 中有定义)
// animal.bark(); // ❌ 不能调用(Animal 中没有定义)
2. 属性没有多态
public class Animal {
public String name = "动物";
}
public class Dog extends Animal {
public String name = "狗";
}
Animal animal = new Dog();
System.out.println(animal.name); // "动物"(不是"狗")
原因:属性访问在编译时确定,方法调用在运行时确定。
3. 静态方法没有多态
public class Animal {
public static void test() {
System.out.println("Animal");
}
}
public class Dog extends Animal {
public static void test() {
System.out.println("Dog");
}
}
Animal animal = new Dog();
animal.test(); // "Animal"(不是"Dog")
小结
Java 多态要点:
- 多态概念:同一接口,不同实现
- 实现方式:方法重写
- 应用场景:方法参数、数组、集合、返回值
- 类型检查:instanceof 运算符
- 优势:代码复用、可扩展性、灵活性
关键要点:
- 多态通过方法重写实现
- 运行时根据实际对象类型调用方法
- 只能调用父类中定义的方法
- 属性没有多态
- 静态方法没有多态
理解了多态,你就能编写更灵活、可扩展的代码。在下一章,我们将学习方法重写与重载的区别。