在Java虚拟机(JVM)中,invokevirtual
是一个字节码指令,用于调用对象实例的方法。它的主要作用是执行对象的虚方法调用,遵循Java语言中的动态分派机制。
例如,假设我们有以下Java代码:
Java
1public class Animal {
2 public void makeSound() {
3 System.out.println("Animal makes a sound");
4 }
5}
6
7public class Dog extends Animal {
8 @Override
9 public void makeSound() {
10 System.out.println("Dog barks");
11 }
12
13 public static void main(String[] args) {
14 Animal myPet = new Dog();
15 myPet.makeSound(); // 这行代码编译后将包含invokevirtual指令
16 }
17}
当JVM执行到 myPet.makeSound()
时,对应的字节码会包含 invokevirtual
指令,它的工作原理如下:
- 首先,根据栈顶的对象引用找到实际的对象类型。在这个例子中,虽然变量
myPet
的静态类型是Animal
,但其实际类型是Dog
。 - JVM查找实际类型
Dog
中名为makeSound
的方法签名,并执行该方法体。 - 如果没有在实际类型中找到对应的方法,则按照继承关系向上查找父类直到找到合适的实现或者到达顶级父类(Object),如果没有找到则抛出
AbstractMethodError
或者NoSuchMethodError
异常。
因此,在上述示例中,尽管通过 Animal
类型的引用调用了 makeSound
方法,但由于运行时的实际对象是 Dog
类型,所以最终执行的是 Dog
类中重写的 makeSound
方法,输出 “Dog barks”。这就是 invokevirtual
指令如何实现在运行时基于对象实际类型的多态性方法调用。