Java中对象方法的调用过程&动态绑定(Dynamic Binding)

Java面向对象的最重要的一个特点就是多态, 而多态当中涉及到了一个重要的机制是动态绑定(Dynamic binding)。

之前只有一个大概的概念, 没有深入去了解动态绑定的机理, 直到很多公司都问到了动态绑定的实现, 然后。。。就真的没有然后了。

痛定思痛, 在<Core Java>找到了相关的章节,也算是对动态绑定的实现有了一个大概的了解。

对象是Java中最重要的概念, 弄清楚对象方法的调用执行过程会对Java对象有更深层了理解。下面是<Core Java>中对调用过程的详细描述:

1. 编译器首先查看对象声明的类型和方法名, 假设对象调用 x.f(param) ,x是声明为C类的对象, 需要注意的是由于存在方法的重载, 所以可能有多个名字为f,

但是参数类型、个数或者次序不一样的方法。 例如 f(int), f(double), f(string)。然后编译器会一一列举出所有C类中方法名为 f 的方法以及C类的父类中属性为public

而且方法名为 f 的方法

至此, 编译器已经获得了所有可能被调用的候选方法。

2.  编译器查看调用方法时传入的参数类型, 然后去上述已经获得的候选方法中进行查找, 如果这些方法中存在一个与提供的参数类型完全匹配的就会选择这个方法

这个过程被称为重载解析(overloading resulution)。 例如调用 x.f("hello"), 编译器会通过重载解析挑选f(string)而不是f(int)。

如果编译器没有找到与参数类型匹配的方法, 就会报告一个错误。

至此, 编译器已经获得需要调用的方法的名字和参数类型。

3. 如果是private, static, final修饰的方法或者构造器(constructor), 那么编译器可以准确的指导应该调用哪个方法, 这种方式称为静态绑定(static binding)

即在编译期间已经把对象和方法进行了绑定 除此之外, 如果调用的方法要一依赖于对象的实际类型, 在运行时实现对象和方法绑定的称为动态绑定(Dynamic binding)。

4. 当程序运行并且采用动态绑定调用方法时, 虚拟机JVM一定会调用与x所引用的对象的实际类型最相符合的那个类的方法。

例如, x的实际类型是C, C是B的子类, 在调用 x.f("hello")时首先会去看C类中是否有 f(string) 方法, 如果有则直接调用, 如果没有则在C类的父类B中寻找f(string)方法。

由于每次调用发发都要进行搜索, 由此带来的后果就是时间开销较大,因此虚拟机采用了一种策略---> 方发表(method table), 其实我感觉就是借用了数据结构中的散列表。

JVM 会预先为每个类都创建一个方法表(method Table)方发表中勒出了所有的签名和实际调用方法。

举个例子,  Java虚拟机预先为 Employee 和 Manager 两个类生成方发表

 medthod Table ----Employee                                                          method Table-----Manager extends Employee

       (签名)           (调用)                                                      (签名)                           (方法调用)  

  getName()     -----> Employee.getName()                                getName()    --------->    Employee.getName()

  getSalary()    -----> Employee.getSalary()          getSalary()   --------->  Manager.getSalary() 

  getHireDay()  -----> Employee.getHireDay()         getHireDay() --------->   Employee.getHireDay()

  raiseSalary()  -----> Employee.raiseSalary()         raiseSalary() --------->  Employee.raiseSalary() 

                                setBounus()  --------->  Manager.setBounus()

如果对 e.getSalary() 精选解析, 过程如下:

1.  JVM 会提取e的实际类型的方发表, 例如是Employee类型则会提取左表, 如果是Manager类型则会提取右表。

2.  JVM 会在方发表中搜索方法的签名, 例如e.getSalary()则会去每个方发表左边的签名列中寻找与getSalary()匹配的方法。

3.  JVM 调用该方法。

原文地址:https://www.cnblogs.com/beyond-Acm/p/4397146.html