静态绑定和动态绑定

多态机制

  多态:在面向对象编程中,某个接口的不同实现,或者说同一个接口使用不同的实例进行不同的操作,下面举一个例子。
  一个父类SuperClass 有不同子类SubClass1,SubClass2,当子类都重写了父类的某个方法。当父类引用指向了不同的子类对象,通过父类引用调用该方法则对应了不同子类对于该方法的实现
父类SuperClass如下所示:

public class SuperClass {
    public void say(){
        System.out.println("This is SuperClass");
    }
}

两个子类如下,都重写了父类的say()

public class SubClass1 extends SuperClass {
    @Override
    public void say() {
        System.out.println("Hello, this is SubClass1");
    }
}
public class SubClass2 extends SuperClass {
    @Override
    public void say() {
        System.out.println("Hello, this is SubClass2");
    }
}

主函数如下所示:声明了三个父类引用,一个指向父类SuperClass实例,其余两个分别指向子类SubClass1,SubClass2实例,从输出中可以看到,虽然三个都是父类引用,但此时调用的say()方法却对应它们各自的实现。

public static void main(String[] args){
        SuperClass superClass = new SuperClass();
        SuperClass subclass= new SubClass();
        superClass.say();
        subclass.say();
    }


为什么会这样呢,由此可以引出本文的主题——Java的绑定机制


  在Java中,绑定可以分为静态绑定和动态绑定,或者称前期绑定和后期绑定。
  静态(前期)绑定即程序编译阶段已经确定,类的实例变量、static变量、static方法、private方法、final方法均属于静态绑定。
  动态(后期)绑定指绑定被推迟到程序运行时。
简单理解,当通过父类引用(即静态类型为父类)访问时,访问的是父类的变量和方法,通过子类引用(即静态类型为子类)访问时,访问的是子类的变量和方法,这称之为静态绑定。
首先是父类,声明了静态变量staticString,实例变量s,静态方法staticMethod(),实例方法say()。

public class SuperClass {
    public static String staticString = "Super class static string";
    public String s = "Super class string";
    public static void staticMethod(){
        System.out.println("Super class static method");
    }

    public void say(){
        System.out.println("Hello, this is SuperClass");
    }
}

然后是子类,子类重写了父类的say()方法,覆盖了成员变量s(关于父子类中同名的静态变量,静态方法还有私有方法,它们之间没有任何关系,不存在重写)。

public class SubClass extends SuperClass {
    public static String staticString = "Sub Class static String";
    public String s = "SubClass Class String";

    public static void staticMethod(){
        System.out.println("Sub class static method");
    }
}

主函数如下所示:

public static void main(String[] args) {
        SuperClass superClass = new SuperClass();
        SuperClass subClass= new SubClass();

        System.out.println("父类引用指向父类对象");
        System.out.println(superClass.s);
        System.out.println(superClass.staticString);
        superClass.staticMethod();
        superClass.say();

        System.out.println("父类引用指向子类对象(即静态类型为父类)");
        System.out.println(subClass.s);
        System.out.println(subClass.staticString);
        subClass.staticMethod();
        subClass.say();
    }

主函数输出如下所示:

从输出结果可以看到,当通过父类引用访问时(静态类型为父类),不管指向的对象是父类类型还是子类类型,此时均为父类实例变量,static变量,static方法。只有子类重写了父类非private方法会进行动态绑定,此时尽管静态类型为父类,调用的却是子类的方法。

动态绑定原理

  动态绑定的实现机制是根据对象的实际类型查找要执行的方法,子类型中找不到的时候再查找父类。 上面代码中通过父类引用subclass执行say()方法时,首先在子类SubClass中寻找say(),找到了则直接执行,否则在父类中寻找。这样就带来了一个问题,当继承的层次比较深时,则调用方法时每次都要从子类一个个往上找,如果要调用的方法位于比较上层的父类,此时效率是比较低的,大多数系统使用一种称为虚方法表的方法来优化调用的效率。

如上图所示,在类加载的时候为每个类创建一个虚方法表,其中记录的是该类对象所有动态绑定的方法及其入口调用地址,每一个方法只有一个表项,当子类重写了父类方法后,只会保留子类的。对于子类SubClass来说,重写了父类SuperClass的say()方法,其虚方法表中的表项指向它自己的代码实现,因此在通过对象动态绑定方法时,不需要从下往上查找每个父类,只需要查找这个表就可以了。

全部评论

相关推荐

感觉这一周太梦幻了,就像一个梦,很不真实~~~感觉这个暑期,我的运气占了99成,实力只有百分之一4.15上午 腾讯csig 腾讯云部门,面完秒进入复试状态4.16下午 美团优选供应链部门,4.18上午发二面4.17晚上 阿里国际一面,纯拷打,面完我都玉玉了4.18下午 阿里国际二面,是我们leader面的我,很轻松~~4.18晚上 约了hr面4.19上午 hr面,下午两点口头oc4.19晚上 意向书说起来我的暑期好像一次都没挂过~~~~~难道我是天生面试圣体?----------------------------------------------------------------------六个月前,我还是0项目0刷题,当时想的是先把论文发出来再去找实习。结果一次组会,老师打破了我的幻想(不让投B会,只让投刊或者A)我拿头投啊!!!然后就开始物色着找实习,顺便做完了mit的6.s081,但是基本上还是没刷过题目-----------------------------------------------------------------------11月  一次偶然的机会,面进了某个耳机厂的手环部门,大概是做嵌入式的,用的是CPP。12月 莫名其妙拿到了国创的面试机会,0基础四天速成java基础!居然也给我面过了hhhhh,可能是面试没写题吧入职国创后的几个月,一直没活,天天搁那看剧,都快忘了还有暑期实习这回事了~~~~命运的齿轮在2.26开始转动,因为这一天美团开了,我开始慌了,因为那时的我什么都不会。lc,八股,sql全部是0进度。然后就开始了女娲补天,上班刷题,下班继续做之前的开源,顺便学一学八股。3月到现在,lc也刷到快200了,一天最多提交了47次~~~~~~~~~~八股根据别人的面经总结和博客,写了快十万字的笔记~~~~~~~~~~简历上的实习经历和开源,也努力去深挖了,写了几万字的记录~~~~~~所以面试的时候,基本上都能cover了,面试官问到的基础基本都会,不基础的我就把他往我会的地方引。结果好像还不错,基本上每个面试官评价都挺好的emmmmmmmm
投递阿里巴巴等公司10个岗位
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务