方法调用的指令说明
以一个简单地继承来说明一下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
| public interface Breathable {
void breath(); }
public class Parent implements Breathable{ public int field = 0;
public int getField(){ return field; }
private void testPrivate(){ System.out.println("父类私有方法"); }
public Parent(int field){ this.field = field; }
public static void testStatic(){
} public final void testFinal(){
}
public void amountField(){ field+=5; }
public Parent(){
}
@Override public void breath() { System.out.println("人当然会呼吸啦"); } }
public class Child extends Parent { public int field = 1;
@Override public int getField(){ return field; }
public void test(){
}
@Override public void amountField(){ field+=5; }
public static void main(String[] args) { Parent p = new Child(); p.amountField(); p.testStatic(); p.testFinal(); Breathable breathable = new Child(); breathable.breath(); System.out.println(p.getField()); System.out.println(p.field);
} }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| 0: new #3 // class com/zhanghe/study/duotai/Child 3: dup 4: invokespecial #4 // Method "<init>":()V 7: astore_1 8: aload_1 9: invokevirtual #5 // Method com/zhanghe/study/duotai/Parent.amountField:()V 12: aload_1 13: pop 14: invokestatic #6 // Method com/zhanghe/study/duotai/Parent.testStatic:()V 17: aload_1 18: invokevirtual #7 // Method com/zhanghe/study/duotai/Parent.testFinal:()V 21: new #3 // class com/zhanghe/study/duotai/Child 24: dup 25: invokespecial #4 // Method "<init>":()V 28: astore_2 29: aload_2 30: invokeinterface #8, 1 // InterfaceMethod com/zhanghe/study/duotai/Breathable.breath:()V 35: getstatic #9 // Field java/lang/System.out:Ljava/io/PrintStream; 38: aload_1 39: invokevirtual #10 // Method com/zhanghe/study/duotai/Parent.getField:()I 42: invokevirtual #11 // Method java/io/PrintStream.println:(I)V 45: getstatic #9 // Field java/lang/System.out:Ljava/io/PrintStream; 48: aload_1 49: getfield #12 // Field com/zhanghe/study/duotai/Parent.field:I 52: invokevirtual #11 // Method java/io/PrintStream.println:(I)V 55: return
|
方法在编译期就可以确定具体的调用版本,且在运行期是不可变的,这样的方法称为非虚方法,静态方法、构造器、final修饰的方法、父类方法都是非虚方法
- invokespecial 调用方法、私有方法以及父类方法时,解析阶段可以唯一确定方法版本
- invokestatic 调用静态方法,解析阶段可以唯一确定方法版本
- invokevirtual 调用虚方法(重写的方法或者可能会重写的方法,如果显示的使用super来调用,则会变成invokespecial)以及final修饰的方法(这是非虚方法)
- invokeinterface 调用接口方法,会在运行时再确定一个实现该接口的对象
- invokedynamic 动态解析出需要调用的方法然后执行(lambda表示式会出现该指令),该指令使得对于动态语言可以一定的支持
虚方法其实是C++中对于多态的一种实现,需要使用virtual 来进行修饰
而在调用虚方法的时候,会去查找虚方法表来查找该方法所对应的实际入口,虚方法是建立在类的方法区的,在类加载的链接阶段被创建并进行初始化
静态方法、私有方法、实例构造器、父类方法再加上被final修饰的方法,这五种方法调用会在类加载的时候就可以把符号引用解析为该方法的直接引用。这些方法统称为”非虚方法”