0%

方法调用的指令说明

方法调用的指令说明

以一个简单地继承来说明一下

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();
// 重写的实例方法 invokevirtual
p.amountField();
// 调用静态方法 invokestatic
p.testStatic();
// 调用父类的final方法 invokevirtual
p.testFinal();

Breathable breathable = new Child();
// 实现的接口方法 invokeinterface
breathable.breath();
//invokevirtual
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 来进行修饰

而在调用虚方法的时候,会去查找虚方法表来查找该方法所对应的实际入口,虚方法是建立在类的方法区的,在类加载的链接阶段被创建并进行初始化