前言:
我们都知道面向对象的三大特性是:封装,继承和多态,并且在继续深入的学习中我们能够发现,封装和继承几乎都是为多态而准备的。因此,想要完全掌握面向对象编程,就需要我们深刻的理解多态这个知识点,而想要达到这个目的,就需要弄明白本文的主角:java的动态绑定机制(DynamicBinding)
引入:
在正式解释Java的动态绑定机制之前,让我们先来看这样一串代码
public class DynamicBinding {
public static void main(String[] args) {
Base b=new Sub();
System.out.println("调用b.sum()方法可以得到:"+b.sum());
}
}
class Base{//父类
public int i=10;
public int sum(){
return getI()+10;
}
public int getI(){
return i;
}
}
class Sub extends Base{//子类
public int i=20;
public int sum(){
return i+20;
}
public int getI(){
return i;
}
}
相信各位小伙伴已经知道结果了吧!这串代码最终的输出结果是:
调用b.sum()方法可以得到:40
至于为什么会打印输出这样的结果,下面就让我们一起来分析一下这其中的调用情况。
首先,从语句Base b=new Sub();中我们能判断出,这里b 的编译类型是 Base,运行类型是 Sub(编译类型看=号左边,运行类型看=号右边)。
但是,从下一条语句System.out.println("调用b.sum()方法可以得到:"+b.sum());开始,可能就有小伙伴开始蒙圈了,因为Base类和Sub类中都有sum()和sum1()方法,到底调用的是Base类中的方法还是Sub类中的方法呢?这就引出了我们的主角:java的动态绑定机制(DynamicBinding)
正文:
java的动态绑定机制:
(1)当调用对象方法的时候,该方法会和该对象的运行类型绑定
(2)当调用对象的属性时,没有动态绑定机制,哪里声明就在哪里使用
因此,回到这串代码中,根据该机制可以知道:
由于对象b的运行类型为Sub,所以,当调用sum()方法时,会优先调用Sub类中的sum()方法。
而sum()方法中返回的属性i;由于没有动态绑定,就直接调用在Sub类中定义的属性i=20;所以就会得到返回值20+20=40,因此输出结果为调用b.sum()方法可以得到:40
事实上,动态绑定机制在多态中的运用十分灵活,为了帮助更好的明白这其中的规则和原理
下面我们就将Sub子类中的sum()方法注释掉,来帮助我们更加深刻的理解。
public class DynamicBinding {
public static void main(String[] args) {
Base b=new Sub();
System.out.println("调用b.sum()方法可以得到:"+b.sum());
}
}
class Base{//父类
public int i=10;
public int sum(){
return getI()+10;
}
public int getI(){
return i;
}
}
class Sub extends Base{//子类
public int i=20;
// public int sum(){
// return i+20;
// }
public int getI(){
return i;
}
}
首先,在System.out.println("调用b.sum()方法可以得到:"+b.sum());语句中,b.sum()调用时会遵循动态绑定机制去调用其运行类型Sub子类中的sum()方法,但是,由于Sub子类中的sum()方法被注释掉了,所以,b.sum()调用时会根据继承机制去他的父类Base类中寻找sum()方法,并执行父类sum()方法中的return getI()+10;语句,但执行getI()方法时,又会产生动态绑定,系统会去执行对象b的运行类型Sub中的getI()方法,继而执行Sub类中的return i;语句,而属性i没有动态绑定机制,因此会调用Sub中声明的属性i;即public int i=20;最终返回的运行结果就是:
调用b.sum()方法可以得到:30
而不是
调用b.sum()方法可以得到:20
如果大家有被绕晕的话,不妨自己写写代码并通过注释一部分代码来验证下自己的思路正不正确,如果我讲述的部分有任何问题,欢迎各位指正。
总结:
动态绑定机制在多态中的运用可以十分的灵活,我们只有弄明白了这其中的逻辑和原理,才能完全的掌握面向对象的思想。最后,当我们创建对象时,一定要搞清楚这个对象的编译类型和运行类型,这样才能帮助我们更好的理解后面的代码逻辑。