JVM-方法的调用(小插曲)

180 阅读2分钟

四、方法的调用

在JVM里面,将符号引用转换为调用方法的直接引用是跟方法的绑定机制有关的。

  • 静态链接 当一个字节码文件装载进JVM内部时,如果被调用的方法在编译期可知,并且在运行期保持不变的情况下,那么这种转换的过程称之为静态链接。

  • 动态链接 当被调用的方法在编译期无法确定,需要在运行期才可知,这种将符合引用转换为方法的直接引用的过程称之为动态链接。

静态链接对应的方法绑定机制为早期绑定;动态链接对应的方法绑定机制为晚期绑定

  • 非虚方法 如果方法在编译期可以确定具体的调用版本,并且运行期是不可变的,那么这种方法称之为非虚方法,像静态方法、私有方法、final方法、实例构造器、父类方法都是非虚方法,对应也就是早期绑定
  • 虚方法 类似于c++里面的虚函数,如果方法在编译器无法确定具体的调用版本,只能在运行期确定,那这种方法就称之为虚方法,与之对应也就是晚期绑定

具体的字节码指令

  • invokestatic:调用static修饰的方法
  • invokespecial:调用方法,私有及父类方法
  • invokevirtual:调用所有的虚方法(注意!final 修饰的是非虚方法)
  • invokeinterface:调用父类接口的方法

jdk 1.8之后引入了动态的调用指令(invokedynamic),这个设计是为了符合lambda表达式而来.

image.png

image.png


/**
 * @author sijing.lu
 * @create 2021/12/7 10:15 上午
 * @description
 * @since 1.0.0
 */
public class JVMMethod {

    class Animal{
        void eat(){
            System.out.println("动物要吃饭");
        }
    }
    interface Hunt{
        void hunt();
    }

    public class Cat extends Animal implements Hunt{

        @Override
        public void eat() {
            System.out.println("猫吃鱼");
        }

        @Override
        public void hunt() {
            System.out.println("猫捉老鼠");
        }
    }

    public class Dog extends Animal implements Hunt{

        @Override
        void eat() {
            super.eat();
        }

        @Override
        public void hunt() {
            System.out.println("狗拿耗子");
        }
    }

    public void showEat(Animal animal){
        // 晚期绑定
        animal.eat();
    }

    public void showHunt(Hunt hunt){
        // 晚期绑定
        hunt.hunt();
    }




    public static void main(String[] args) {
        JVMMethod method = new JVMMethod();
        method.methodA();

        method.methodB();
        methodC();

    }

    public void methodA(){
        System.out.println("methodA()");
    }

    public final void methodB(){
        System.out.println("methodB()");
    }

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

}