一、方法调用
java程序进行各种方法调用,虚拟机提供了不同的字节码指令进行方法调用。
1、普通调用指令:
非虚方法调用指令:
- invokespecial:调用< init >方法、私有以及父类方法
- invokestatic:调用静态方法,解析阶段确定唯一方法
虚方法调用指令: - invokevirtual:调用所有虚方法
- invokeinterface:调用接口方法
注意:被final修饰的方法,虽然是invokevirtual指令调用,但依然为非虚方法
2、动态调用指令
- invokedynamic:调用动态方法,java7开始出现,为实现动态类型语言支持而做出的改进。在java8中,使用lambada表达式之后进行反汇编即可观察到使用的invokedynamic指令。
3、虚方法和非虚方法
非虚方法:
- 如果这个方法在编译器就确定了具体的调用版本,在运行时是不可以变的,称之为非虚方法。
- 静态方法、私有方法、final方法、实例构造器、父类方法都是非虚方法
虚方法:
除了非虚方法的其它方法都为虚方法。
e.g.:我们在使用多态的时候,是动态绑定,编译期间并不知道调用的是子类的方法还是父类的方法,只有在运行时才能确定下来。
二、案例
package page2.virtual;
public class Father {
public Father() {
System.out.println("父类构造器");
}
public static void showStatic(String string){
System.out.println("父类" + string);
}
public final void showFinal(){
System.out.println("父类 final方法");
}
public void showCommon(){
System.out.println("父类普通方法");
}
}
package page2.virtual;
public interface MethodInterface {
void method();
}
package page2.virtual;
public class Son extends Father{
public Son(){
super();
}
public Son(String string){
super();
System.out.println("子类" + string);
}
private void showPrivate(String string) {
System.out.println("子类 室私有" + string);
}
public static void showStatic(String string) {
System.out.println("子类 " + string);
}
public void info(){
}
public void display(Father f){
f.showCommon();
}
public void show() {
//invokestatic
showStatic("Sanford so handsome");
//invokestatic
super.showStatic("Sanford");
//invokespecial
showPrivate("handsome");
//invokespecial
super.showCommon();
//invokevirtual
showFinal();//因为此方法声明有final,不能被子类重写,所以也认为此方法是非虚方法。
//虚方法如下:
//invokevirtual
showCommon();
//invokeinterface
MethodInterface methodInterface = null;
methodInterface.method();
}
public static void main(String[] args) {
Son son = new Son();
son.show();
}
}
使用javap反汇编
public page2.virtual.Son(java.lang.String);
descriptor: (Ljava/lang/String;)V
flags: ACC_PUBLIC
Code:
stack=3, locals=2, args_size=2
0: aload_0
1: invokespecial #1 // Method page2/virtual/Father."<init>":()V
4: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
7: new #3 // class java/lang/StringBuilder
10: dup
11: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V
14: ldc #5 // String 子类
16: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
19: aload_1
20: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
23: invokevirtual #7 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
26: invokevirtual #8 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
29: return