java多态运行时实现

java多态的三个必要条件:一要有继承,二要有重写,三要有父类引用指向之类对象;当多态的时候,虽然调用的是父类里面的方法,但实质上调用的是指向对象的所属类里面的已经重写的方法,注意的是这个方法必须和父类里面的需要重写的方法完全一致;在内存中,jvm根据编译后的字节码指令,将入口地址指向了你需要的子类方法实现。至于private私有方法,子类是获取不到的,即使子类写的一样,但是还是不属于重写,就是说他们两个方法已经没有任何的关系了(基类私有方法与多态)。


方法调用相关的jvm子令集主要有一下四种:
 
invokestatic ------------------------------->调用类方法(静态绑定,速度快)
 
invokevirtual ------------------------------>调用实例方法(动态绑定)
 
invokespecial ----------------------------->调用实例方法(静态绑定,速度快)
 
invokeinterface --------------------------->调用引用类型为interface的实例方法(动态绑定)
 
invokedynamic --------------------------->JDK 7引入的,主要是为了支持动态语言的方法调用。可参考
New JDK 7 Feature: Support for Dynamically Typed Languages in the Java Virtual Machine,java从静态语言过渡到动态语言。
 
操作码  			操作数					说明
invokestatic		indexbyte1,indexbyte2		把args从stack中弹出,调用constant method pool索引指向的实例方法
 
invokevirtual		indexbyte1,indexbyte2		把objectref和args从stack中弹出,调用constant method pool索引指向的实例方法
 
invokespecial		indexbyte1,indexbyte2		把objectref和args从stack中弹出,调用constant method pool索引指向的实例方法
 
invokeinterface	indexbyte1,indexbyte2		把objectref和args从stack中弹出,调用constant method pool索引指向的实例方法
 
//-----------------------------------------------举例浅析区别----------------------------------------------------------------
invokevirtual和invokespecial的区别在于:invokespecial通常根据引用的类型选择方法,而不是实际对象的类型来选择!即它使用静态绑定而不是动态绑定。
 
使用invokespecial指令分为下面三种情况:
1. 实例初始化方法(<init>())方法
2. 私有方法
3. 使用super关键字调用的方法
 
 
invokespecial and Private Methods
看下面一个例子:
 
Java代码 
class Superclass {  
    private void interestingMethod() {  
        System.out.println("Superclass's interesting method.");  
    }  
   
    void exampleMethod() {  
        interestingMethod();  
    }  
}  
  
class Subclass extends Superclass {  
    void interestingMethod() {  
        System.out.println("Subclass's interesting method.");  
    }  
   
    public static void main(String args[]) {  
        Subclass me = new Subclass();  
        me.exampleMethod();  
    }  
}  
 
 Here are the bytecodes for the main() method of class Subclass:
Bytecode代码 
0:   new     #5; //class Subclass  
3:   dup  
4:   invokespecial   #6; //Method "<init>":()V  
7:   astore_1  
8:   aload_1  
9:   invokevirtual   #7; //Method exampleMethod:()V  
12:  return  
 Subclass从Superclass处继承了exampleMethod()方法。当Subclass的me对象调用exampleMethod()时使用的是invokevirtual。JVM会创建一个新的栈帧并将其压入栈,然后执行exampleMethod()的bytecode。下面是exampleMethod()的bytecode:
Bytecode代码
0:   aload_0  
1:   invokespecial   #5; //Method interestingMethod:()V  
4:   return  
exampleMethod()首先将赋给局部变量0的reference压入stack(隐含参数this被传入给所有的实例方法),然后使用invokespecial指令通过这个引用调用interestingMethod()。
尽管这里的对象时Subclass的实例,而且Subclass类中的interestingMethod()方法也是能够访问的,但是JVM最终还是调用了Superclass类中的interestingMethod()方法。
程序的正确输出为:"Superclass's interesting method",因为这里生成的bytecode中调用的interestingMethod()使用的是invokespecial指令,而调用invokespecial指令时,JVM会按照你reference type来choice调用的method。
 
//-----------------------------------------------------------------指令调用和速度PK-------------------------------------------------------
可想而知,调用接口引用方法可能要比调用类引用方法慢。因为,当JVM遇到invokevirtual指令时,它把实例方法的符号引用解析为直接引用,所以生成的直接引用很可能是方法表中的一个偏移量,而且从此往后都可以使用同样的偏移量。但对于invokeinterface指令来说,虚拟机每一次遇到invokeinterface指令,都不能不重新搜寻一遍方法表,因为虚拟机不能够假设这一次的偏移量与上一次的偏移量相同。
最快的指令莫过于invokespecial和invokestatic,因为这些指令调用的都是静态绑定的,即在编译器确定了!所以当JVM为这些指令解析符号引用时,将符号引用转换成为直接饮用,所生成的直接引用将包含一个指向实际操作码的指针。
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值