多态(polymorphism)是“同一个调用,对不同对象产生各自行为”。调用方写一次 employee.getSalary(),全职员工按基本工资加奖金计算,兼职员工按时薪乘工时计算。循环不需要堆叠类型判断,职责留在各个对象内部。
如果这些对象共享父类,共同方法就像一份明确约定;Java 还支持基于接口的多态:即使没有共同父类,只要类实现了调用方需要的接口,也能参与同一段代码。
同名方法,不同实现
本节按“一类一个文件”组织代码,接口也单独保存。文件名与类型名一致;同一组示例的文件放在同一目录,不同组示例请使用独立目录,避免同名类互相冲突。
Employee.java
public abstract class Employee {
abstract double getSalary();
}FullTimeEmployee.java
public class FullTimeEmployee extends Employee {
private final String name;
private final double salary;
private final double bonus;
FullTimeEmployee(String name, double salary, double bonus) {
this.name = name;
this.salary = salary;
this.bonus = bonus;
}
@Override
double getSalary() {
return salary + bonus;
}
}PartTimeEmployee.java
public class PartTimeEmployee extends Employee {
private final String name;
private final double wage;
private final double hours;
PartTimeEmployee(String name, double wage, double hours) {
this.name = name;
this.wage = wage;
this.hours = hours;
}
@Override
double getSalary() {
return wage * hours;
}
}Main.java
public class Main {
public static void main(String[] args) {
Employee[] employees = {
new FullTimeEmployee("Alice", 5783, 173),
new PartTimeEmployee("Bob", 150, 15)
};
for (Employee employee : employees) {
System.out.println(employee.getSalary());
}
}
}互动实验
多态工资站:同一段循环,不同的计算
访问权限PRO
PRO EXCLUSIVE探索不止于此
尊享 Pro 权益解锁完整互动实验、进阶解析与精选参考答案。
知识测验
题目
同一条 getSalary() 调用为何会使用不同公式?
知识测验
题目
多态给调用方带来的主要好处是什么?
接口与可扩展性
Report、Invoice 和 GradeSheet 不一定属于同一种事物,但都可以实现 Exportable 并提供 export()。exportAll() 只依赖这个行为。以后新增 Receipt,只要也实现 Exportable,就无需修改循环。接口会让缺少方法的问题在编译时出现,因此约定保持明确。
基于接口的多态关心对象“能做什么”,而不只关心它“是什么”。
Exportable.java
public interface Exportable {
String export();
}Main.java
public class Main {
static void exportAll(Exportable[] items) {
for (Exportable item : items) {
System.out.println(item.export());
}
}
}这里的 Main.java 先只定义辅助方法 exportAll(),尚未加入程序入口;后面的练习会补上实现接口的类和 main()。
知识测验
题目
接口与父类引用首先关注什么?
知识测验
题目
给 exportAll() 增加新类型,最关键的条件是什么?
动手练习
统一计算不同员工工资
- 实现 FullTimeEmployee 和 PartTimeEmployee。
- 两者都提供 get_name() 与 getSalary()。
- 放进同一列表,只用一个循环打印姓名和工资。
动手练习
接口与父类引用批量导出
- 创建 Report、Invoice、GradeSheet,彼此无需继承。
- 每个类都实现 export() 并返回不同文本。
- 编写 exportAll(items),只用 item.export()。
- 新增 Receipt 类,证明 exportAll 无需修改。