Java的多态

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()),编译和运行阶段均执行父类的方法版本,无多态效果。

相关推荐
证能量少女2 小时前
2026大专Java开发工程师,考什么证加分?
java·开发语言
FPGAI2 小时前
Java学习之基础概念
java·学习
芒克芒克2 小时前
Java集合框架总结(面试八股)
java·开发语言·面试
ejjdhdjdjdjdjjsl3 小时前
C#文件流操作技巧
java·开发语言·spring
虾说羊3 小时前
HashMap详解
java
lkbhua莱克瓦243 小时前
反射3-反射获取构造方法
java·开发语言·反射
wanghowie3 小时前
02.04.01 Java Stream API 进阶指南:从底层实现到性能优化
java·开发语言·性能优化
专注于大数据技术栈3 小时前
java学习--Date
java·学习
superman超哥3 小时前
仓颉元编程进阶:编译期计算能力的原理与深度实践
开发语言·后端·仓颉编程语言·仓颉·仓颉语言·仓颉元编程·编译器计算能力