方法调用绑定--前期绑定和后期绑定

时间:2022-03-02 12:22:47

1、将一个方法调用同一个方法主体关联起来被称作绑定

2、若程序在执行前进行绑定,由编译器和链接程序实现,叫做前期绑定。C语言中只有一种方法调用,就是前期绑定。

3、在运行时根据对象的类型进行绑定,叫做后期绑定,也叫动态绑定运行时绑定

4、Java中除了static方法final方法(private方法被自动认为是final方法)之外,其他所有的方法都是后期绑定。

这句话很重要,在我们使用多态时,即将子类对象赋给父类引用时,通过父类引用调用某一方法。这个时候就会出现“方法调用绑定”问题(这是面向对象程序设计的最重要的妙诀)。如果此方法不是static或者final(private)的,那么绑定是后期绑定,即在编译时(在编译期,只是确保调用方法的存在,并对调用参数和返回值执行类型检查),方法调用和方法体没有关联起来,只要到了运行时,根据引用所指向的对象类型,将方法调用和方法体关联起来。在这个过程中有许多值得注意的地方。父类中有一个方法f(),如果子类中Override了父类的f()方法,那么在运行期方法调用关联到的方法体是子类中的f(),如果子类没有Override父类的f(),那么在运行期方法调用关联到的方法体是子类从父类中继承过来的f()。大家有没有想过一种情况:假如父类中没有f()方法,子类中有,在多态中,方法调用f()时,会出现什么情况呢?其实大家可以做一下实验,结果就是会编译出错!其实很好理解,因为在编译期,编译器只知道,父类引用调用了f()方法,如果父类中没有f()方法,当然会编译出错呀!

一般情况说完了,说一下特殊的情况,关于final的,首先看一下下面的例子:

package com.sailang.polymorphism;

public class PrivateOverride
{
private void f()
{
System.out.println("private f()");
}

public static void main(String[] args)
{
PrivateOverride po = new Derived();
po.f();
}

}

class Derived extends PrivateOverride
{
public void f()
{
System.out.println("public f()");
}
}

大家觉得结果会是什么呢?

结果是private f()。如果各位看懂了我上面的讲解,应该就不难理解了吧!PrivateOverride中的f()方法时private的,即是final的,po.f()是前期绑定,在编译期方法调用就直接绑定到了PrivateOverride的f()方法体上了。进一步分析,PrivateOverride的f()方法时final的,从继承角度考虑,子类是不会继承f()方法的。Derived中的f()方法是一个全新的方法。

 

如果方法是static的,看下面的例子:

package com.sailang.polymorphism;

public class StaticPolymorphism
{
public static void main(String[] args)
{
StaticSuper sup = new StaticSub();

System.out.println(sup.staticGet());
System.out.println(sup.dynamicGet());
}
}

class StaticSuper
{
public static String staticGet()
{
return "Base staticGet()";
}

public String dynamicGet()
{
return "Base dynamicGet()";
}
}

class StaticSub extends StaticSuper
{
public static String staticGet()
{
return "Derived staticGet()";
}

public String dynamicGet()
{
return "Derived dynamicGet()";
}
}

结果很容易知道!

不过我想问一下大家,子类中的dynamicGet()是Override了父类的dynamicGet()方法,对吧!那么子类中的staticGet()方法覆盖了父类的staticGet()方法了吗?大家可以做一下实验。我实验的结果是,static方法既不能被覆盖也不能被继承!不知道这个结论对不对!

5、后期绑定是java中实现的多态的基础。注意多态只是对方法调用起作用的,对域(成员变量)是不起作用的,即对域的调用是编译器解析的。(这方面的知识,我就不写了,大家可以参考《Java编程思想》中文第四版的P156-157)