本文用java来概述动态绑定机制, Scala与java的动态绑定机制是相同的.
package zhang.shao;
public class Demo1 {
public static void main(String[] args) {
Fu fu = new Zi();
System.out.println(fu.getResult());
}
}
class Fu{
public int i = 10;
public int getResult(){
return i + 10;
}
}
class Zi extends Fu{
public int i = 20;
@Override
public int getResult(){
return i + 20;
}
}
结果为: 40
可以看到运行结果为 40, 例子中子类重写了父类的getResult方法, 当代码执行的时候, 执行的是子类的getResult方法, 可以为什么会执行子类的getResult方法呢?? 平时我们都知道 子类重写了父类的方法, 执行的就是子类的方法, 这都是常态了, 可是你们有没有想过,为什么会执行子类重写父类的方法? 本文章就讲述讲述.
package zhang.shao;
public class Demo1 {
public static void main(String[] args) {
Fu fu = new Zi();
System.out.println(fu.getResult());
}
}
class Fu{
public int i = 10;
public int getResult(){
return i + 10;
}
}
class Zi extends Fu{
public int i = 20;
}
结果为: 20
看到结果为20, 可是为什么是20?
接着往下看
从上所述:
图中所示, Fu类有getResult方法, Zi类有getResult方法, 但由于有继承关系, Zi类有两个getResult方法, 一个是父类的方法, 一个是自己的方法., 那么当调用getResult方法, JVM会调用父类的方法,还是自己的方法.那么调用谁是不确定的,所以就有一套规则在里面. 即动态绑定机
动态绑定机制
1.成员方法在执行的过程中, JVM会将方法和当前调用对象实际内存进行绑定,
2.属性没有动态绑定机制.属性在哪里声明就在哪里使用, 靠的是this
第一个例子:
Fu fu = new Zi()
fu.getResult()
当调用getResult方法时, 会看变量fu所指向的实际内存中的对象是谁, 实际内存就是 new出来的Zi类的对象。并不看变量fu的类型是Fu, 只看实际内存, 就是new出来的实际内存, 当知道实际内存为Zi的对象, JVM就会把实际内存的对象与getResult方法绑定, 此时调用的方法就是Zi类对象里面的getResult方法,就不会调用Fu类中的getResult方法. 此时输出结果为: 40.
补充一点: 属性是没有动态绑定机制,靠的是this. 此时getResult方法里的this是Zi类型的, this代表本类的引用, 也就是变量所在的类的引用, 比如, 变量a所在worker类, 此时方法里的this是worker类型的引用, 代表本类的引用.
第二个例子:
Fu fu = new Zi()
fu.getResult()
当调用getResult方法, jvm依然会使用动态绑定机制, 首先会看变量fu所指向的实际内存的对象是谁, 然后看出实际内存中的对象为Zi类对象, 然后判断Zi对象里面是否有getResult方法, 从源代码中可以看到Zi类中没有getResutl方法, 但是Zi类是继承Fu类, Zi类中的getResult方法是从Fu类继承过来的, 所以Zi类是有getResult方法, JVM没有报错, 此时执行的父类的getResult方法, gerResult方法里的变量i靠的是this来指定, 此时this是本类的引用,也就是说this的类型为Fu类型,此时this.i代表的是Fu类中的i, this.i可以省略this. 直接写i就可以, 此时i为10,返回为20。
再看一个例子:
package zhang.shao;
public class Demo1 {
public static void main(String[] args) {
Fu fu = new Zi();
System.out.println(fu.getResult());
}
}
class Fu{
public int i = 10;
public int getResult(){
return getI() + 10;
}
public int getI(){
return i;
}
}
class Zi extends Fu{
public int i = 20;
@Override
public int getI(){
return i;
}
}
结果: 30
当调用getResult方法, JVM会采用动态绑定机制, 会根据变量fu所指向的实际内存里的对象, 使其与getResult方法进行绑定, 实际内存里的对象为Zi类的对象, 由于Zi类继承Fu类, 所以Zi类有getResult方法, 这个getResult方法是从父类中继承过来的, 相当于子类有了getResult方法, 此时执行的getResult方法里的代码体是父类中的getResult方法里内容, 当执行getI方法时, JVM仍然会采用动态绑定机制, 会根据实际内存中的对象,使其与getI方法来进行绑定, 从源码中可以看出,子类中是有getI方法, 此时子类的getI方法会和实际内存中的对象进行绑定. 那么就会子类中的getiff,而不会执行父类的getI方法.
总结一下:
只要是调用方法就要遵循动态绑定机制,无论是直接调用还是间接调用,都会遵循动态绑定机制, 就要根据实际内存中的对象来与方法进行绑定!最终就会执行 动态绑定之后的方法. 如果子类没有重写, 而父类有这个方法, 而这个动态绑定仍然会遵循!子类仍然有这个方法, 只不过子类的方法是从父类中继承过来的, 由于方法是从父类那里继承的, 那么执行的代码体就是父类中的方法里的代码体. 而属性是靠this来执行的, 通过this的类型来指定属性值