Bootstrap

java中的虚拟方法和非虚拟方法


一、方法调用

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

;