java中的动态绑定和静态绑定

来源:互联网 发布:方正字库 mac 编辑:程序博客网 时间:2024/04/30 10:31

public class TestOverwrite {
        public static void main(String []args){
                Father father = new Son();
                Son son = new Son();
                father.show(son); //show:Son:father
                father.display(son); //display:Father:father
        }
}
class Father{
        void show(Father father){
                System.out.println("show:Father:father");
        }
        static void display(Father father){
                System.out.println("display:Father:father");
        }
}
class Son extends Father{
        void show(Father father){
                System.out.println("show:Son:father");
        }
        void show(Son father){
                System.out.println("show:Son:son");
        }
        static void display(Father father){
                System.out.println("display:Son:father");
        }
}

答案很好给出,自己在eclipse里跑一下也能知道个一二,网上有人讨论过类似问题深入理解java多态性 ,这篇文章将多态性和重载混在一起,涉及了很多种情况,作者也给出了自己的分析“实际上这里涉及方法调用的优先问题 ,优先级由高到低依次为:this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)”,这个顺序没错,但我这里想探究下为什么是这个顺序。

Java和很多面向对象语言一样有静态绑定static-binding和动态绑定dynamic-binding两种方式,静态绑定发生于程序的编译期,动态绑定发生于程序的运行期,最直观的两个例子:重载,重写。重载发生于编译期,是静态绑定的一种,静态绑定根据函数签名进行绑定,决定最终运行哪个函数;动态绑定在运行期根据多态的机制重新决定运行哪个函数。

回到上面的程序,Father father = new Son(); 这句代码初始化了一个Father类型的引用,它指向了一个Son类型的对象,但因为向上转型的原因,在变量father看来它指向的堆空间其实是一个Father,内存图如下:
内存图,图中a为father懒得改了
内存图,图中a为father懒得改了

那么在函数编译时,father.show(b)首先查询father所指对象的函数列表,发现只有 void show(Father a); 一个函数,并且形参类型符合转型需求,与其绑定,当运行时,因为多态机制,发现void show(Father a); 函数在子类中被重写了,覆盖了父类的方法,于是动态与子类重写后的方法绑定,便得到了这样的运行结果。当然子类中另一个重载的show方法是进行迷惑的,编译时其根本不在father能调用的函数表里,一早被淘汰,后面也就没它什么事儿。

再来看看display函数,父类和子类中有签名相同的display函数,与show不同的是有static关键字,static在没有实例化时变产生,所以看似是重写,其实根本不是,也就没多态的事儿,所以编译时根据函数签名静态绑定到了父类的display,后面没有动态绑定的过程,故输出结果是父类的display的结果。

参考资料:
1.Dynamic Binding and Static Binding
2.常见Java面试题 – 第三部分:重载(overloading)与重写(overriding)

转载自: http://www.douban.com/note/272520236/
0 0
原创粉丝点击