java 多态

365在线登录app 📅 2026-07-21 16:43:21 ✍️ admin 👁️ 6822 ❤️ 252
java 多态

Java 中的多态(Polymorphism),是面向对象三大特性(封装、继承、多态)之一,也是面试中最常考的知识点。

很多人认为多态就是“父类引用指向子类对象”,其实这只是多态的表现形式,不是它的本质。

多态的本质:同一个接口(方法调用),根据对象的不同,表现出不同的行为。

例如:

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("猫吃鱼");

}

}

调用:

Animal animal = new Dog();

animal.eat();

输出

狗吃骨头

如果换成

Animal animal = new Cat();

animal.eat();

输出

猫吃鱼

可以看到:

同样都是

animal.eat();

由于实际对象不同,执行的代码也不同。

这就是多态。

多态成立的三个条件

Java 中实现运行时多态,必须满足三个条件。

① 有继承(Inheritance)

class Animal {}

class Dog extends Animal {}

没有继承,就不存在多态。

② 有方法重写(Override)

父类

public void eat() {

}

子类

@Override

public void eat() {

}

如果没有重写:

class Animal{

public void eat(){

System.out.println("Animal");

}

}

class Dog extends Animal{

}

调用

Animal animal = new Dog();

animal.eat();

输出仍然是

Animal

因为 Dog 没有自己的实现。

③ 父类引用指向子类对象

Animal animal = new Dog();

而不是

Dog dog = new Dog();

只有

Animal animal = new Dog();

Java 才需要运行时去判断到底执行哪个方法。

Java 多态是如何实现的?

很多人只停留在

父类引用指向子类对象

真正面试官更喜欢问:

JVM 是如何实现多态的?

答案就是:

动态绑定(Dynamic Dispatch)+ 虚方法表(Virtual Method Table,vtable)

第一步:编译阶段

例如:

Animal animal = new Dog();

animal.eat();

编译器只知道:

animal 的类型是 Animal

因此生成的字节码:

invokevirtual Animal.eat()

注意:

编译器不知道最终对象是不是 Dog。

第二步:运行阶段

真正执行时

JVM 会发现:

animal

实际上指向 Dog 对象

于是:

Dog.eat()

而不是

Animal.eat()

这就是

动态绑定(Dynamic Binding)

即:

方法到底调用哪个版本,不是在编译时决定,而是在运行时决定。

JVM 是如何找到 Dog.eat() 的?

JVM 内部,每个类都有一个

虚方法表(Virtual Method Table)

例如:

Animal

Animal VTable

eat() -----> Animal.eat()

sleep() ---> Animal.sleep()

run() -----> Animal.run()

Dog

Dog VTable

eat() -----> Dog.eat()

sleep() ---> Animal.sleep()

run() -----> Animal.run()

Dog 重写了 eat

所以

eat()

Dog.eat()

没有重写的方法

sleep()

Animal.sleep()

调用

animal.eat();

实际上流程就是:

animal

找到对象

找到对象所属Class

找到VTable

查eat()

Dog.eat()

执行

所以:

Java 多态,本质就是 JVM 在运行期间根据对象实际类型查找虚方法表并完成动态绑定。

为什么成员变量没有多态?

例如:

class Animal{

String name = "Animal";

}

class Dog extends Animal{

String name = "Dog";

}

Animal animal = new Dog();

System.out.println(animal.name);

输出

Animal

很多新人都会觉得应该输出 Dog。

实际上:

成员变量没有重写,只有隐藏(Hide)。

变量访问:

animal.name

编译器已经知道:

animal

Animal

因此直接访问

Animal.name

变量访问属于

静态绑定(Static Binding)

不会发生动态绑定。

为什么 static 方法没有多态?

class Animal{

static void eat(){

System.out.println("Animal");

}

}

class Dog extends Animal{

static void eat(){

System.out.println("Dog");

}

}

调用:

Animal animal = new Dog();

animal.eat();

输出

Animal

原因:

static 属于类。

调用的是:

Animal.eat()

不是对象。

因此:

静态方法不能重写

只能隐藏。

为什么 final 方法没有多态?

class Animal{

final void eat(){

}

}

子类

不能Override

既然不能 Override,

自然不存在动态绑定。

private 方法为什么没有多态?

private 方法:

子类不可见

不能 Override。

因此

private 方法

编译时就确定

invokeSpecial

不是 invokevirtual。

Java 中多态有哪些实现方式?

Java 中的多态主要有以下几种:

实现方式是否运行时多态原理

方法重写(Override)

✅ 是

动态绑定(Dynamic Dispatch)

接口实现(Interface)

✅ 是

不同实现类执行不同逻辑

抽象类

✅ 是

子类实现抽象方法

方法重载(Overload)

❌ 否

编译期多态(静态多态)

泛型

❌ 否

参数类型约束,不属于多态机制

例如接口:

interface Payment{

void pay();

}

class AliPay implements Payment{

public void pay(){

System.out.println("支付宝");

}

}

class WechatPay implements Payment{

public void pay(){

System.out.println("微信");

}

}

Payment payment = new AliPay();

payment.pay();

payment = new WechatPay();

payment.pay();

调用代码完全一样:

payment.pay();

但实际行为不同,这也是典型的运行时多态。

生产中的经典应用

以支付系统为例,不同支付渠道都实现统一接口:

public interface PayService {

void pay(Order order);

}

public class AlipayService implements PayService {

@Override

public void pay(Order order) {

// 支付宝支付

}

}

public class WechatPayService implements PayService {

@Override

public void pay(Order order) {

// 微信支付

}

}

public class UnionPayService implements PayService {

@Override

public void pay(Order order) {

// 银联支付

}

}

业务层无需关心具体实现:

PayService payService = getPayService(channel);

payService.pay(order);

新增一种支付方式(如 PayPal)时,只需新增一个实现类,而无需修改原有业务逻辑。这体现了多态带来的可扩展性,也符合开闭原则(对扩展开放,对修改关闭)。

面试回答模板(2 分钟)

Java 的多态指的是同一个方法调用,在运行时根据对象的实际类型表现出不同的行为。实现运行时多态需要满足三个条件:继承、方法重写、父类(或接口)引用指向子类对象。编译阶段,编译器只知道引用类型,会生成 invokevirtual 等调用指令;运行阶段,JVM 根据对象的实际类型,通过动态绑定查找对应类的虚方法表(vtable),最终调用真正的方法实现。需要注意的是,成员变量、static 方法、final 方法和 private 方法都不参与运行时多态,因为它们不是通过动态绑定进行调用。在实际项目中,多态广泛应用于支付、消息通知、策略模式、工厂模式等场景,可以显著提高系统的扩展性和维护性。

相关创意

天王卡咪咕定向流量使用范围,咪咕视频免流怎么激活
乐山玩的地方有哪些,乐山网红打卡景点
如何减少qq占用手机内存 手机QQ瘦身方法
最新公布:日本平均月薪达33万日元!(约1 万 6 千人民币)你达标了吗?
真空胎如何修补
地球一天为何是精准的24小时,闰年和闰秒就是时间的副作用
每集1分钟、追剧花百元:上头短剧如何收割观众
爱情日志 15
电动车雅迪多少钱