Java:方法的虚分派(virtual dispatch)和方法表(method table)
Java:方法的虚分派(virtual dispatch)和方法表(method table)
背景知识:
java 字节码基本框架,jvm基本框架
多态的机制。
Virtual Dispatch
首先从字节码中对方法的调用说起。
java的bytecode中对方法的调用实现分为四种情况:
1.invokevirtual 为最常见的情况,包含virtual dispatch机制;
2.invokespecial是作为private和构造方法的调用,绕过了virtual dispatch;
3.invokeinterface的实现跟invokevirtual类似。
4.invokestatic是对静态方法的调用。
其中最复杂的要属 invokevirtual .
virtual dispatch机制会首先从 receiver(调用该方法的对象)的类的实现中查找对应的方法,如果没找到,则去父类查找,直到找到函数并实现调用,而不是依赖于引用类型。
下面是一段有趣的代码。反映了virtual dispatch机制 和 一般的field访问的不同。
- public class Greeting {
- String intro = "Hello";
- String target(){
- return "world";
- }
- }
- public class FrenchGreeting extends Greeting {
- String intro = "Bonjour";
- String target(){
- return "le monde";
- }
- public static void main(String[] args){
- Greeting english = new Greeting();
- Greeting french = new FrenchGreeting();
- System.out.println(english.intro + "," + english.target());
- System.out.println(french.intro + "," + french.target());
- System.out.println(((FrenchGreeting)french).intro + "," + ((FrenchGreeting)french).target());
- }
- }
- Hello,world
- Hello,le monde
- Bonjour,le monde
对于intro这个filed的访问,直接指向了父类中的变量,因为引用 类型为父类。
而对于target的方法调用,则是指向了子类中的方法,虽然引用类型也为父类,但这是virtual dispatch的结果,virtual dispatch不管引用类型的,只查receiver的类型。
既然 虚分派 机制是从receiver对象的子类开始查找,由此看来,对于一个覆盖了父类中某方法的子类的对象,是无法调用父类中那个被覆盖的方法的吗?
在虚分派机制中这确实是不可以的。但却可以通过invokespecial实现。如下代码
- public class FrenchGreeting extends Greeting {
- String intro = "Bonjour";
- String target(){
- return "le monde";
- }
- public String func(){
- return super.target();
- }
- public static void main(String[] args){
- Greeting english = new Greeting();
- FrenchGreeting french = new FrenchGreeting();
- System.out.println(french.func());
- }
- }
- ALOAD 0: this
- INVOKESPECIAL Greeting.target() : String
- ARETURN
|
评论暂时关闭