写在前面
本文来看下jvm方法调用相关的4个指令invokestatic,invokespecial,invokeinterface,invokevirutal。
1:如何来记
1.1:静态绑定和动态绑定
如果是在编译期就能确定要调用的方法,就叫做静态绑定,比如构造函数方法,静态方法,private方法。
如果是必须在运行期才能确定要调用的方法,就叫做动态绑定,比如基于接口的引用调用的方法。
我们可以首先按照静态绑定还是动态绑定来对一个方法调用进行分类,然后再根据具体情况判断其对应的指令什么:
- 如果判定是静态绑定
如果是静态方法:则是invokestatic指令
如果不是静态方法:则是invokespecial指令,包括构造函数,private方法,super关键字的方法调用
- 如果判定是动态绑定
如果引用是接口,则是invokeinterface指令
如果不是接口(类,抽象类),则是invokevirtual指令
这样是不是很好记了,接下来再看个例子。
首先定义一个接口和一个类:
package org.example;
public interface I1 {
public void fn1();
default void fn2() {}
}
package org.example;
public class B1 {
void fn3(){
}
}
再定义一个类实现接口,继承类:
package org.example;
public class S1 extends B1 implements I1 {
public static void main(String[] args) {
// 构造函数对应INVOKESPECIAL指令
I1 t1 = new S1();
// 实例私有方法对应INVOKESPECIAL指令
((S1)t1).privateFn();
// 静态方法对应INVOKESTATIC
sayHi();
// 基于接口引用调用接口定义的抽象方法,对应INVOKEINTERFACE指令(动态绑定)
t1.fn1();
// 构造函数对应INVOKESPECIAL指令
B1 b1 = new S1();
// 基于接口引用调用接口定义的抽象方法,对应INVOKEVIRTUAL指令(动态绑定)
b1.fn3();
}
public S1() {}
// 实例私有方法,对应invokespecial
private void privateFn() {
}
// 静态方法,对应invokestatic指令
public static void sayHi() {
}
@Override
public void fn1() {
}
}
接着我们来使用bytecode outline插件来查看字节码:
具体可以对比来看下。
写在后面
参考文章列表
字节码编程ASM之idea插件asm bytecode outline的使用