基础数据

IName

public interface IName {
    public String getName();
}

AA

public class AA implements IName{
    @Override
    public String getName() {
        return "AA";
    }

    public static void staticFun(){
        System.out.println();
    }
}

Main类

public static void main(String[] args) {
    IName name = new AA();
    name.getName(); // invokeinterface

    AA aa = new AA();
    aa.getName(); // invokevirtual

    AA.staticFun(); // invokestatic
}

字节码

 0 new #2 <itable/AA>
 3 dup
 4 invokespecial #3 <itable/AA.<init>>
 7 astore_1
 8 aload_1
 9 invokeinterface #4 <itable/IName.getName> count 1
14 pop
15 new #2 <itable/AA>
18 dup
19 invokespecial #3 <itable/AA.<init>>
22 astore_2
23 aload_2
24 invokevirtual #5 <itable/AA.getName>
27 pop
28 invokestatic #6 <itable/AA.staticFun>
31 return
invokeinterface

接口调用
itable

IName name = new AA();
name.getName(); // invokeinterface
invokevirtual

非接口调用
vtable

AA aa = new AA();
aa.getName(); // invokevirtual
invokestatic

调用静态方法

AA.staticFun(); // invokestatic
invokespecial
<init>等方法
invokespecial #3 <itable/AA.<init>>
对比
指令 调用方 调用方式
invokeinterface 通过接口调用 (itable)
invokevirtual 非接口、非静态、非special调用 (vtable)
invokestatic 调用静态方法 直接调用
invokespecial <init> 直接调用