当我们站在JVM实现的角度去看方法调用的时候,我们自然会想到一种分类:
1、编译代码的时候就知道是哪个方法,永远不会产生歧义,例如静态方法,private方法,构造方法,super方法。
2、运行时才能确定是哪个方法,这也正是多态的实现原理。
对于第一种方法的调用,有2个字节码指令:invokestatic,invokespecial
invokestatic:调用static方法(不需要通过类的实例就可以调用),这很好理解。静态方法属于整个类型,就一份,没有歧义。
invokespecial:调用private方法、构造方法,super方法。private方法是不会被子类继承下去的,所以不会有歧义,这和通过super去调用父类的方法是一个道理。
对于第二种方法的调用,有2个字节码指令:invokevirtual,invokeinterface
invokevirtual:这部分的方法运用了方法表,对方法表中的方法的直接引用表现为偏移量(1、2、3.....),我认为这就像是数据库中的索引。在子类的方法表中,从父类继承下来的方法总是在方法表的前面,而子类重写的方法在方法表中指向自己的实现,于是多态得以实现。当调用方法时,JVM通过具体的对象引用找到实际类,进而找到正确的方法。
invokeinterface:和invokevirtual的实现一样,但是针对接口的方法的实现,在各个实现类的方法表中,不能通过偏移量来快速查找,因为各个方法表中的偏移量可能不相同,只能全表扫描,所以速度会慢很多。
tips:A a = new B(),这里的A叫做静态类型,B叫做实际类型,A针对第一种调用,B针对第二种调用。
参考《深入理解Java虚拟机》