Java和Scala的动态绑定机制

本文用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的类型来指定属性值

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值