方法调用的原理:
方法调用的本质是通过字节码指令的执行在栈上创建栈帧,并调用方法中的字节码执行。
invoke方法的核心就是找到字节码指令并执行。
invoke指令执行时,需要找到方法区中instanceklass中保存的方法相关的字节码信息,但是方法区中有很多类,每一个类有很多方法,通过静态绑定或动态绑定精准找到方法的位置。
1.静态绑定
编译期间,invoke指令会携带一个参数符号引用,引用到常量池中的方法定义,方法定义中包含了类名+方法名+返回值+参数。方法第一次调用时,这些符号引用就会被替换成内存地址的直接引用,这种方式成为静态绑定。(如查看字节码文件,在执行方法对应的invoke语句中,后面会跟一个符号引用,引到常量池中的方法定义。常量池中包含了类名,名字和描述符)
静态绑定适用于处理静态方法、私有方法,或者final修饰的方法,因为这些方法不能被继承之后重写。继承后重写会出现多态,静态绑定无法处理多态。
2.动态绑定
对于非static、非private、非final的方法,有可能存在子类重写方法,需要动态绑定来完成方法中地址绑定的工作。
创建Cat对象并把其类型转化为Animal,调用该对象的eat方法,字节码文件中引用的是Animal类的eat方法(因为是Animal类型的对象),静态绑定只能通过常量池中的内容找到Cat里面的eat方法。
动态绑定:
如果子类重写了父类的方法则调用子类的方法,否则调用父类的方法。