Java的多态
Java的多态
Java 中的多态(Polymorphism)是面向对象编程(OOP)三大核心特性之一,其核心定义为:同一操作作用于不同的对象时,能根据对象的实际类型展现出不同的行为逻辑或执行结果。
多态的分类
Java 多态分为两类核心形态:
编译时多态(静态多态)
编译器在编译阶段即完成方法调用与具体实现的绑定,绑定结果仅依赖于方法调用的参数列表和引用的声明类型,与对象的运行时类型无关。
编译时多态的实现方式是方法重载(Overloading),重载指在同一个类中可以有多个方法,这些方法名称相同但参数列表不同(参数数量或类型不同),编译器通过严格匹配方法调用时的参数信息,确定要执行的方法版本。
运行时多态(动态多态)
方法调用与具体实现的绑定延迟到程序运行阶段,根据对象实际类型而非引用声明类型确定方法执行版本,这是 Java 多态最核心最常用的形态。
典型表现:当子类继承父类(或实现类实现接口),且按规则重写 父类 / 接口 的非私有、非 final、非 static 方法后,若使用父类类型引用指向子类对象(或接口类型引用指向实现类对象),调用该重写方法时,JVM 会通过对象头中的类型指针解析对象的实际运行时类型,进而执行子类 / 实现类的重写方法版本,而非父类 / 接口的原始方法版本。
多态实现方式示例
编译时多态
编译时多态的实现方式是方法重载(Overloading)
重载指在同一个类中可以有多个方法,这些方法名称相同但参数列表不同(参数数量或类型不同),以下是一个重载示例
java
public class Calculator {
// 重载1
public int add(int a, int b) { return a + b; }
// 重载2
public int add(int a, int b, int c) { return a + b + c; }
// 重载3
public double add(double a, double b) { return a + b; }
}
运行时多态
运行时多态的核心实现要素为方法重写(Method Override,前提条件) 与向上转型(执行载体),其生效需同时满足以下三个必要条件:
存在类的继承关系或类对接口的实现关系;
子类 / 实现类按规则重写父类 / 接口的方法:方法签名完全一致、返回值类型兼容、访问权限不缩小,且被重写方法不能是私有(private)、最终(final)、静态(static)方法;
完成向上转型:使用父类类型的引用指向子类类型的对象(或接口类型的引用指向实现类对象)。
类型转型是多态场景中引用类型与对象实际类型关联的核心操作,分为向上转型和向下转型两类:
- 向上转型(自动转型,运行时多态的必要条件)
核心语法:Parent child = new Child();
引用变量的类型决定可访问的成员范围,堆中实际实例的类型决定方法的执行逻辑。
编译阶段编译器仅依据child的声明类型(Parent)校验可调用的方法 / 成员,而运行阶段 JVM 会根据引用指向的实际实例类型(Child)执行方法逻辑,若Child重写了Parent的方法,执行子类重写后的逻辑,未重写则执行父类原逻辑。 - 向下转型(强制转型,多态场景的补充手段)
核心语法:SubClass obj = (SubClass) superObj;
作为向上转型的反向操作,向下转型是将父类类型的引用显式转换为子类类型的引用,编译器不会自动完成,必须显式声明转型类型;
转型前必须通过 instanceof 关键字检查,验证引用所指向对象的实际运行时类型是否与目标子类类型兼容,否则运行时会抛出 ClassCastException 异常;
适用场景:仅当需要通过父类引用调用子类特有且未在父类中定义的方法时,才需通过向下转型还原精准类型;
关键说明:向下转型不改变对象的实际运行时类型,不影响运行时多态的核心逻辑,仅作为多态场景下访问子类特有行为的补充手段。
抽象类是实现运行时多态的常用父类载体,下面进行代码实现
java
public abstract class Service {
protected String serviceName;
// 构造方法
public Service(String serviceName) {
this.serviceName = serviceName;
}
// 抽象方法
public abstract void execute();
// 普通方法
public void preCheck() {
System.out.println("【通用前置检查】" + serviceName + ":验证请求参数、权限校验");
}
// 普通方法
public String getServiceName() {
return serviceName;
}
}
抽象类定义统一的业务规范(抽象方法),强制子类实现差异化逻辑
定义多个子类,每个子类重写父类的execute()方法,实现不同的业务逻辑
java
public class OrderService extends Service {
// 子类特有属性
private String orderNo;
// 构造方法:调用父类构造与初始化子类特有属性
public OrderService(String orderNo) {
super("订单服务");
this.orderNo = orderNo;
}
// 重写抽象方法
@Override
public void execute() {
System.out.println("【订单服务-" + orderNo + "】创建订单、扣减库存、生成物流单");
}
// 子类特有方法(演示多态下的向下转型)
public String queryOrderStatus() {
return "订单[" + orderNo + "]:已创建,待支付";
}
}
java
public class PayService extends Service {
// 子类特有属性
private double amount;
private String payType;
// 构造方法:调用父类构造与初始化子类特有属性
public PayService(double amount, String payType) {
super("支付服务");
this.amount = amount;
this.payType = payType;
}
// 重写抽象方法
@Override
public void execute() {
System.out.println("【支付服务】验证金额[" + amount + "元]、调用" + payType + "支付接口、更新订单支付状态");
}
// 子类特有方法(演示多态下的向下转型)
public String getPayResult() {
return payType + "支付[" + amount + "元]:支付成功";
}
}
java
public class RefundService extends Service {
// 子类特有属性
private String refundNo;
private String relatedOrderNo;
// 构造方法:调用父类构造与初始化子类特有属性
public RefundService(String refundNo, String relatedOrderNo) {
super("退款服务");
this.refundNo = refundNo;
this.relatedOrderNo = relatedOrderNo;
}
// 重写抽象方法
@Override
public void execute() {
System.out.println("【退款服务-" + refundNo + "】审核退款申请、返还[" + relatedOrderNo + "]订单金额、更新退款状态");
}
// 子类特有方法(演示多态下的向下转型)
public String getRefundProgress() {
return "退款单[" + refundNo + "]:已到账,关联订单[" + relatedOrderNo + "]";
}
}
测试类(核心演示运行时多态)
java
import java.util.ArrayList;
import java.util.List;
// 测试类:完整演示多态的核心特性
public class RuntimePolymorphismTest {
public static void main(String[] args) {
// 父类引用指向子类对象
Service service1 = new OrderService("ORDER_20251226_001");
Service service2 = new PayService(999.0, "支付宝");
Service service3 = new RefundService("REFUND_20251226_001", "ORDER_20251226_001");
// 调用重写的execute方法(运行时多态核心:编译看父类,运行看子类)
System.out.println("===== 场景1:基础多态调用 =====");
service1.execute(); // 实际执行OrderService的execute
service2.execute(); // 实际执行PayService的execute
service3.execute(); // 实际执行RefundService的execute
// 多态下的向下转型(需要时调用子类特有方法)
System.out.println("\n===== 场景4:多态下的向下转型 =====");
if (service1 instanceof OrderService) {
OrderService orderService = (OrderService) service1; // 向下转型
System.out.println(orderService.queryOrderStatus()); // 调用子类特有方法
}
if (service2 instanceof PayService) {
PayService payService = (PayService) service2;
System.out.println(payService.getPayResult());
}
}
// 统一的服务处理方法:参数为父类类型,适配所有子类(多态的核心价值体现)
public static void processService(Service service) {
System.out.println("\n=== 开始处理[" + service.getServiceName() + "] ===");
service.preCheck();
service.execute(); // 调用子类重写的业务逻辑(运行时多态)
System.out.println("=== [" + service.getServiceName() + "]处理完成 ===\n");
}
}
执行结果如下:

(1)编译阶段:静态检查,仅关注引用的声明类型
编译器校验 service1.execute() 时,仅检查抽象父类 Service 是否包含 execute() 方法(抽象方法已定义,编译通过),不关心引用实际指向的子类类型;若父类未定义该方法(如调用子类特有方法 queryOrderStatus()),编译器会直接报错(需向下转型后才能调用)。
(2)运行阶段:动态绑定,仅关注对象的实际类型
JVM 通过动态绑定机制(解析对象头中的类型指针),识别 service1 实际指向 OrderService 对象,最终执行 OrderService 重写的 execute() 方法;对于非重写方法(如 preCheck()),编译和运行阶段均执行父类的方法版本,无多态效果。