动力节点旗下在线教育品牌  |  咨询热线:400-8080-105 学Java全栈,上蛙课网
首页 > 文章

动态绑定与静态绑定

07-24 17:19 240浏览
举报 T字号
  • 大字
  • 中字
  • 小字

动态绑定与静态绑定java类中的非常重要的机制,本文主要关于动态绑定与静态绑定相关知识

首先,弄清调用对象方法的执行过程十分重要。下面是调用过程的详细描述

1)编译器査看对象的声明类型和方法名。假设调用x.f( param),且X被声明为C类的对象。需要注意的是:有可能存在多个名字为,但参数类型不一样的方法。例如,可能存在方法(n)和方法(String)。编译器将会一一列举所有C类中名为的所有方法和其超类中访问属性为 public且名1为的方法。至此,编译器已获得所有可能被调用的侯选方法。

2)编译器査看调用方法时提供的参数类型。如果在所有名为的方法中存在一个其参数类型与提供的参数完全匹配,那么就调用这个方法。这个过程被称为重载解析( overloadingresolution)。例如,对于调用x.f(Hello”)来说,编译器将会挑选f(String),而不是f(int)。由于允许类型转(int可以转换 double, Manager可以转换成 Employee等等),所以这个过程可能很复杂。如果编译器没有找到与参数类型匹配的方法,或者发现经过类型转换后有多个方法与之匹配,就会报告一个错误。至此,编译器已获得需要调用的方法的名字和参数类型。

注意:前面曾经说过,方法的名字和参数列表被称为方法的签名( signature)。例如,f(int)和f(string)是两个具有相名字,不同名的方法,果在子类中定义了一个与超类签名相同的方法,那么子中的这个方法就就覆盖了超类中的这个同签名的方法。不过,返回类型不是签名的一部分,因此在覆盖方法的时候,一定要保证返回类型的兼容性。在JDK5.0以前的版本中,要求返回类型必须是一样的。而现在允许子类将覆盖方法的返回类型定义为原返回类型的子类型。例如,假设

employee类有

public Employee getBuddy(){...}

在后面的子类 Manager中,可以接照如下所示的方式覆盖这个方法:

public Manager getBuddy(){...}//OK in JDK 5.0

我们说,这两个getBudy方法具有可协变的( covariant)返回类型。

3)如果方法是private、static、final或者构造器那么器可以准确道应该调用哪个方法。我们将这种调用方式称为静态绑定static binding)。与之对应,调用哪个方法将依赖于隐式参数的实际类型,并且在运行时动态绑定。在上面列举的例子中,编译器就是采用动态绑定的方式生成一条调用f( String)的指令。

4)当程序运行,并且采用动态绑定调用方法时,虚拟机一定调用与x所引用对象的实际类型最合适的那个类的方法。假设x的实际类型是D,它是C类的子类。如果D类定义了方法(String),就直接调用它;否则,将在D类的超类中寻找方法( String),以此类推。

每次调用方法都要进行搜索,时间开销相当大。因此,虚拟机预先为每个类创建了一个方法表( method table),其中列出了所有方法的签名和实际调用的方法。这样一来,在真正调用方法的时候,虚拟机仅査找这个表就行了。在前面的例子中,虚拟机捜素D类的方法表,以便寻找与调用f(String相匹配的方法。这个方法既有可能是D.f( String),也有可能是X.( String),这里的X是D的超类。这里需要提醒一点,如果调用super.f (param),编译器将对隐式参数超类的方法表进行搜索

现在让我们分析一下调用e.getSalary()的详细过程。e声明为Employee类型。 Employee类只有一个名叫getSalary的方法,这个方法没有参数。因此,在这里我们不必担心重载解析的问题。

由于getSalary不是private、staticfinal方法,所以将采用动态绑定,虚机为EmployeeManager两个类生成方法表。在Employee的方法表中,列出了这个类定义的所有方法:

Employee:

getName()->Employee.getName()

getSalary()->Employee.getSalary()

getHireDay()->Employee. getHireDay()

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

实际上,上面列出的方法并不完整,稍后会看到 Employee类有一个超类Object, Employee类从这个超类中还继承了许多方法。在此,我们略去了这些方法。

Manager方法表稍微有些不同。共中有三个方法是继承而来的,一个方法是重新定义的,还有一个方法是新增加的。

Manager

getName()->Employee, getName()

getSalary()- Manager. getSalary()

getHireDay()-> Employee.getHireDay()

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

setBonus(double)-> Manager.setBonus( double)

在运行的时候,调用e. getSalary()的解析过程为:

  • 虚拟机提取e的实际类型的方法表。既可能是Employee、Manager的方法表,也可能是Employee类的其他子类的方法表。
  • 虚拟机搜索定义getSalary签名的类。此时,虚拟机已经知道应该调用哪个方法。
  • 虚拟机调用方法。

动态绑定有一个非常重要的特性:无需对现存的代码进行修改,就可以对程序进行扩展。假设增加一个新类 Executive,并且变量e有可能引用这个类的对象。我们不需要对包含调用e.getSalary()代码进行重新编译。如果恰好引用一个 Executive类型的对象,就会自动地调用Executive. getSalar()方法。

:在覆盖一个方法的时候、子类方法不能低于超类方法的可见性。特别是,果超类方法是 public,那么子类方法一定要声明为 public。经常会发生这类错误:在声明子方法的时候,遗漏public修饰符。此时,编译器将会把它解释为试图减弱访问权限。

动态绑定与静态绑定是java基础知识中必须掌握的核心技术,如果你还没有完全掌握,不要担心,本站的java视频课程当中有更详细地讲解等你来看。

0人推荐
共同学习,写下你的评论
0条评论
无心出岫
程序员无心出岫

10篇文章贡献51071字

作者相关文章更多>

推荐相关文章更多>

Java数据结构

HelloWorld10-31 08:24

浅谈MySQL中SQL优化的常用方法

军哥08-12 23:29

五分钟读懂UML类图

江湖人称小李白12-10 10:41

MyBatis开发框架的四大核心

IT逐梦者08-17 21:43

一次搞定continue,break和return

HelloWorld11-06 11:19

发评论

举报

0/150

取消