Java 多态

Java 多态(Polymorphism)超详细解析
(从零基础到面试八股 + 底层原理 + 最佳实践)

多态是 Java 面向对象三大特性(封装、继承、多态)中最重要、最灵活的一个,被称为“面向对象编程的灵魂”。几乎每场 Java 面试都会被问到。

1. 什么是多态?

一句话定义
同一个行为(方法),在不同对象上具有不同的表现形式,即“一种行为,多种形态”。

通俗理解
同一个“叫”方法,狗叫“汪汪”,猫叫“喵喵”,人叫“说话” —— 这就是多态。

2. 多态的三个必要条件(背诵重点!)

  1. 继承(或实现接口):子类继承父类或实现接口。
  2. 重写(Override):子类重写父类的方法。
  3. 父类引用指向子类对象(向上转型):
   父类类型 引用变量名 = new 子类类型();

缺少任意一个,都无法构成多态。

3. 多态的两种表现形式

(1)方法重写(Override) —— 运行时多态(最重要)

// 父类
class Animal {
    public void makeSound() {
        System.out.println("动物叫声");
    }
}

// 子类1
class Dog extends Animal {
    @Override
    public void makeSound() {
        System.out.println("汪汪汪");
    }
}

// 子类2
class Cat extends Animal {
    @Override
    public void makeSound() {
        System.out.println("喵喵喵");
    }
}

public class Test {
    public static void main(String[] args) {
        Animal a1 = new Dog();   // 向上转型
        Animal a2 = new Cat();

        a1.makeSound();   // 输出:汪汪汪
        a2.makeSound();   // 输出:喵喵喵
    }
}

关键:编译时看左边(Animal),运行时看右边(实际类型 Dog / Cat)。

(2)方法重载(Overload) —— 编译时多态(静态多态)

同一个类中,方法名相同,参数列表不同。

class Calculator {
    public int add(int a, int b) { ... }
    public double add(double a, double b) { ... }
    public int add(int a, int b, int c) { ... }
}

4. 多态的向上转型与向下转型

Animal animal = new Dog();        // 向上转型(自动)
Dog dog = (Dog) animal;           // 向下转型(需强制)

// 安全向下转型写法(推荐)
if (animal instanceof Dog) {
    Dog d = (Dog) animal;
}

5. 多态的优点(为什么需要多态?)

  • 扩展性强:新增子类不需要修改原有代码(开闭原则)。
  • 代码简洁:统一用父类类型操作不同子类对象。
  • 可维护性高:符合“面向接口/抽象编程”思想。

经典应用场景

  • 工厂模式、策略模式、模板方法模式
  • List list = new ArrayList<>();(接口引用指向实现类)
  • Spring 中的依赖注入(@Autowired 接口类型)

6. 多态的底层实现原理(面试追问高频)

Java 多态主要依赖 虚方法调用(动态绑定 / 晚绑定)。

过程

  1. JVM 在方法区为每个类建立虚方法表(vtable)。
  2. 虚方法表中存放实际要调用的方法入口地址。
  3. 调用时:
  • 通过对象头中的类型指针找到实际对象类型。
  • 在该类型的虚方法表中查找方法地址。
  • 执行。

注意

  • staticprivatefinal构造方法 的方法不是虚方法,属于静态绑定(编译时确定)。
  • final 方法不能被重写,因此没有多态。

7. 多态经典面试题

Q1:多态的三个必要条件是什么?
答:继承、重写、父类引用指向子类对象。

Q2:编译时多态和运行时多态的区别?

  • 编译时多态(静态):方法重载,根据参数类型和个数决定调用哪个方法。
  • 运行时多态(动态):方法重写,根据实际对象类型决定调用哪个方法。

Q3:下面代码输出什么?为什么?

Father f = new Son();
System.out.println(f.age);   // 输出 40(父类的age)

class Father {
    int age = 40;
}

class Son extends Father {
    int age = 20;
}

答:输出父类的 age。因为属性没有多态,属性访问看左边(编译时类型)。

Q4:成员变量、静态方法、普通方法在多态中的表现?

成员是否有多态访问规则
普通方法编译看左,运行看右
成员变量编译看左,运行看左
静态方法编译看左,运行看左

8. 多态最佳实践

// 推荐写法:面向接口/抽象类编程
List&lt;String> list = new ArrayList&lt;>();   // 而不是 ArrayList list = new ArrayList&lt;>();

// 策略模式示例
public void pay(PaymentStrategy strategy, double amount) {
    strategy.pay(amount);   // 不同的支付方式(支付宝、微信、银行卡)
}

不推荐

  • 过度使用 instanceof(破坏多态,代码丑陋)
  • 所有方法都写成 final(失去扩展性)

总结口诀(背诵版)

多态三条件:有继承,要重写,父类引用指子类。
编译看左边运行看右边,属性静态无多态。
虚方法表实现动态绑定,final/static 不参与。
面向接口编程,扩展维护真方便!


Java 多态部分到此结束。这是面向对象编程中最核心的内容之一。

想继续深入吗?我可以立刻给你:

  • 下一节:Java 抽象类 vs 接口(区别 + 使用场景 + JDK8+ 默认方法)
  • 完整多态案例:支付系统、图形计算器、动物园管理系统代码
  • 面试真题:多态相关 20 道高频题 + 答案
  • 与 Go 接口对比(你之前学过 Go 接口)

直接回复:

  • “抽象类和接口”
  • “多态实战代码”
  • “多态面试题”
  • 或其他你想学的 Java 主题(如“异常处理”、“集合框架”等)

继续加油!多态掌握好了,设计模式和框架源码学习会轻松很多!

文章已创建 5130

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部