一、invokevirtual指令
invokevirtual #3 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
在Java虚拟机中,invokevirtual指令是用来调用对象实例方法的指令。它的操作码是0xb6,操作数需要指定要调用的方法的符号引用。invokevirtual指令在解析阶段进行动态绑定,即在执行该指令时再决定具体要调用的方法。
在上面的示例中,我们调用了PrintStream对象的println方法,我们可以通过符号引用的方式传递方法的参数信息和返回值信息。在执行时,Java虚拟机会查找并调用对应的println方法。
二、invokevirtual_quick
invokevirtual_quick #3 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
在invokevirtual指令的执行过程中,Java虚拟机需要进行方法查找和动态绑定,这个过程可能比较耗时。为此,Java虚拟机引入了invokevirtual_quick指令来进行快速调用。
在调用同一个类中的方法时,invokevirtual_quick指令能够直接找到方法并调用,因此这个过程会更加快速。需要注意的是,如果在子类中重写了父类的这个方法,那么当使用invokevirtual_quick指令时,依然会调用父类的方法。
三、invokevirtual过程
Java虚拟机在执行invokevirtual指令时,需要进行以下步骤:
Step1. 查找符号引用所对应的方法。
Java虚拟机首先通过符号引用中的类信息,查找该类或其父类中是否存在符合方法签名的方法,并返回方法的直接引用。
Step2. 检查访问权限。
如果找到了方法的直接引用,Java虚拟机需要检查当前类是否有权限访问该方法。
Step3. 进行动态绑定。
如果访问权限检查通过,Java虚拟机需要判断该方法是否为虚方法,并进行动态绑定。动态绑定的过程中,Java虚拟机会查找符合该对象实际类型的方法,如果找到,则调用这个方法。
四、invokevirtual指令的含义
invokevirtual指令主要用于调用对象实例方法,它能够在运行时动态绑定方法,保证程序的灵活性与扩展性。而invokevirtual_quick指令则更加高效,适用于同一个类中的方法调用。
五、invokevirtual和invokeinterface
invokevirtual指令和invokeinterface指令都用于调用接口或类中的方法,它们之间的区别在于invokeinterface指令在调用前需要先通过接口映射指针表(ITable)查找接口方法所对应的方法,在动态绑定时也需要进行接口方法表(VTable)的查找。
由于invokeinterface指令需要进行两次表的查找,因此其速度要比invokevirtual指令慢,同时还要注意接口映射指针表中方法的顺序和排列方式对性能的影响。
完整示例代码
public class Example { public static void main(String[] args) { Parent parent = new Child(); parent.foo(); } } class Parent { public void foo() { System.out.println("Parent"); } } class Child extends Parent { public void foo() { System.out.println("Child"); } }
原创文章,作者:小蓝,如若转载,请注明出处:https://www.506064.com/n/220048.html