jvm是怎样调用方法的

jvm内部有五种调用方法的指令

invokeinterface	用以调用接口方法,在运行时搜索一个实现了这个接口方法的对象,找出适合的方法进行调用。(Invoke interface method)
invokevirtual	指令用于调用对象的实例方法,根据对象的实际类型进行分派(Invoke instance method; dispatch based on class)
invokestatic	用以调用类方法(Invoke a class (static) method )
invokespecial	指令用于调用一些需要特殊处理的实例方法,包括实例初始化方法、私有方法和父类方法。(Invoke instance method; special handling for superclass, private, and instance initialization method invocations )
invokedynamic	JDK1.7新加入的一个虚拟机指令,相比于之前的四条指令,他们的分派逻辑都是固化在JVM内部,而invokedynamic则用于处理新的方法分派:它允许应用级别的代码来确定执行哪一个方
invokestatic和invokespecial是在编译器确定的,他们适用于不会发生重写的情况
invokevirtual和invokeinterface	是虚方法,这两个指令在调用时,通过一张方法表来调用。

看两个类

public class Animal {
    protected void sleep(){
        System.out.println("动物能睡觉");
    }
}





public class Bird extends Animal implements Fly {
    @Override
    protected void sleep() {
        System.out.println("鸟会睡觉");
    }

    @Override
    public void fly() {
        System.out.println("鸟会飞");
    }

    public static void print() {
        System.out.println("这是鸟");
    }
}


两个类对应的方法表

animal的方法表

0
sleep

bird方法表

0sleep
1 fly

如果重写父类的方法,父类方法的index和子类的一致,方便查找。

由上可知,使用继承或实现会让程序变慢,因为需要查方法表,但是没有必要因为慢而放弃面向对象良好的设计,因为这个时间很短并且jvm还有针对虚方法的优化,内联缓存。

内联缓存举个例子来说

Animal animal = new Bird();

animal.sleep();

这个时候jvm缓存下bird对象和sleep方法,下次bird对象想要调用sleep方法时,缓存里存了bird的方法就不用去查表了。

 

posted @ 2019-02-03 12:07  刘皓lh  阅读(650)  评论(0编辑  收藏  举报