MST
星途 面试题库

面试题:Java多态在JVM内存模型中的体现

结合JVM的内存模型,阐述Java多态在运行时,对象的内存布局、方法表等是如何协同工作以实现多态特性的。
36.7万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

Java多态运行时对象内存布局、方法表协同工作原理

  1. JVM内存模型相关区域
    • 堆(Heap):对象实例都在堆中分配内存。在Java多态场景下,不同类型的对象(父类引用指向子类实例)都存储于堆中。例如,Animal animal = new Dog();Dog对象在堆中创建,它包含了Dog类自身以及从Animal类继承的成员变量。
    • 方法区(Method Area):存储类的元数据,包括类的结构信息(如字段、方法等)、常量池等。对于多态涉及的类,其类信息都在方法区,比如Animal类和Dog类的元数据。其中,方法区中还包含了方法表,方法表用于快速定位方法。
  2. 对象内存布局
    • 对象头:包含两部分,一部分是Mark Word,用于存储对象的运行时元数据,如哈希码、对象分代年龄、锁状态标志等信息;另一部分是类型指针,指向方法区中该对象所属类的元数据,通过这个指针可以找到类的方法表等信息。在多态中,不同子类对象的对象头中的类型指针指向各自对应的类元数据。例如,Dog对象的类型指针指向Dog类在方法区的元数据。
    • 实例数据:存储对象的成员变量,包括从父类继承来的和子类自己定义的。例如Dog对象的实例数据包含从Animal类继承的name等变量,以及Dog类自己可能定义的barkVolume等变量。
    • 对齐填充:不是必须的,由于JVM要求对象起始地址必须是8字节的整数倍,当对象实例数据部分没有对齐时,就需要通过对齐填充来补全。
  3. 方法表
    • 方法表结构:方法表是类在方法区的元数据的一部分,它是一个数组,每个元素是一个指向方法在方法区内存位置的指针。在多态中,子类的方法表会包含从父类继承的方法以及子类重写或新增的方法。例如,Dog类的方法表中,对于重写的makeSound方法,其指针指向Dog类中重写后的makeSound方法的实现;对于从Animal类继承且未重写的方法,指针指向Animal类中该方法的实现。
    • 方法表的构建:在类加载的链接阶段,JVM会为每个类构建方法表。对于父类的方法,子类方法表中会继承,如果子类重写了该方法,方法表中对应位置的指针会更新为指向子类重写的方法。这样在运行时,通过对象的类型指针找到类的方法表,就能根据方法表中指针快速定位到实际要执行的方法。
  4. 多态特性的实现
    • 编译期:Java编译器在编译时,根据引用类型(即声明的变量类型)来确定可以调用的方法。例如,Animal animal = new Dog();,编译器只知道animalAnimal类型,所以只能确定Animal类中定义的方法可以调用。但是对于重写的方法,编译器会做一些标记,以便运行时能够正确调用子类的方法。
    • 运行期:当实际执行方法调用时,JVM首先根据对象的对象头中的类型指针找到对象所属类的方法表。然后在方法表中查找要调用的方法对应的指针,找到后调用该指针指向的实际方法。例如,animal.makeSound();,运行时JVM根据Dog对象的类型指针找到Dog类的方法表,由于makeSound方法被重写,方法表中makeSound方法的指针指向Dog类重写后的makeSound方法实现,从而实现多态特性,调用的是Dog类的makeSound方法,而不是Animal类的。