美文网首页技术文
Java之动态绑定与静态绑定

Java之动态绑定与静态绑定

作者: 时光风铃 | 来源:发表于2016-08-05 10:17 被阅读813次

    1、当子类和父类存在同一个方法,子类重写了父类的方法,程序在运行时调用方法是调用父类的方法还是子类的重写方法呢?
    2、当一个类中存在方法名相同但参数不同(重载)的方法,程序在执行的时候该如何辨别区分使用哪个方法呢?
    在Java中我们使用静态绑定(static binding)和动态绑定(Dynamic binding)来解决,那么什么是绑定?什么是静态绑定?什么又是动态绑定?有什么区别?

    绑定、静态绑定、动态绑定的概念

    • 绑定

      绑定指的是一个方法的调用与方法所在的类(方法主体)关联起来。
      对java来说,绑定分为静态绑定和动态绑定;或者叫做前期绑定和后期绑定。

    • 静态绑定

      在程序执行前方法已经被绑定,针对java简单的可以理解为程序编译期的绑定;
      java当中的方法只有final,static,private和构造方法是前期绑定

    • 动态绑定

      在运行时根据具体对象的类型进行绑定。提供了一些机制,可在运行期间判断对象的类型,并分别调用适当的方法。也就是说,编译器此时依然不知道对象的类型,但方法调用机制能自己去调查,找到正确的方法主体。

    动态绑定的过程:
    虚拟机提取对象的实际类型的方法表;
    虚拟机搜索方法签名;
    调用方法。
    

    静态绑定 VS 动态绑定

    1、静态绑定是发生在编译阶段;而动态绑定是在运行阶段;
    2、private, final and static方法和变量使用静态绑定,而虚函数(virtual methods)则会根据运行时的具体对象进行绑定(注:在Java语言中, 所有的方法默认都是”虚函数”。只有以关键字 final 标记的方法才是非虚函数。)
    3、静态绑定使用的是类信息,而动态绑定使用的是对象信息
    4、重载方法(overloaded methods)使用的是静态绑定,而重写方法(overridden methods)使用的是动态绑定
    

    下面从代码中分析

    静态绑定

    public class StaticBindingTest {
    
        public static void main(String args[])  {
            StaticBindingTest sbt = new StaticBindingTest();
            sbt.test("This is a String");
            sbt.test(10);
         }
    
        public void test(String s) {
            System.out.println(s);
        }
    
        public void test(int a) {
            System.out.println(a);
        }
    }
    

    输出结果

    This is a String
    10
    

    从上面的结果可以得出:

    在两个同名但参数不同的方法(重载),在调用方法sbt.test(param)时,程序会自动根据输入的参数类型来选择具体调用哪个方法,其后的原理就是静态绑定,即在编译期根据参数类型进行静态绑定。
    

    java当中的向上转型或者说多态是借助于动态绑定实现的,所以理解了动态绑定,也就搞定了向上转型和多态。

    动态绑定的典型发生在父类和子类的转换声明之下:

    比如:Parent p = new Child();
    其具体过程细节如下:
    1:编译器检查对象的声明类型和方法名。假设我们调用p.method()方法,并且p已经被声明为Child类的对象,那么编译器会列举出Child类中所有的名称为method的方法和从Child类的父类继承过来的method方法
    2:接下来编译器检查方法调用中提供的参数类型。如果在所有名称为method 的方法中有一个参数类型和调用提供的参数类型最为匹配,那么就调用这个方法,这个过程叫做“重载解析” 
    3:当程序运行并且使用动态绑定调用方法时,虚拟机必须调用同p所指向的对象的实际类型相匹配的方法版本。假设child类定义了mehod()那么该方法被调用,否则就在child的父类(Parent类)中搜寻方法method()
    

    动态绑定

    子类有父类的重写方法
    //父类
    public class Parent {
    
        protected String name = "ParentName";
    
        public void method() {
            System.out.println("ParentMethod");
        }
    }
    
    //子类
    public class Child extends Parent {
        protected String name = "ChildName";
    
        public void method() {
            System.out.println("ChildMethod");
        }
    
        public static void main(String[] args) {
            Parent p = new Child();
            System.out.println(p.name);
            p.method();
        }
    }
    

    输出结果

    ParentName
    ChildMethod
    
    子类中没有父类的重写方法
    //测试类
    public class DynamicBindingTest {
    
        public static void main(String[] args) {
            Parent p = new Child();
            System.out.println(p.name);
            p.method();
        }
    }
    
    //父类
    class Parent {
    
        protected String name = "ParentName";
        
        public void method() {
            System.out.println("ParentMethod");
        }
    }
    
    //子类
    class Child extends Parent {
        protected String name = "ChildName";
        
    }    
    

    输出结果:

    ParentName
    ParentMethod
    

    从上面的结果中可以看出:

    1、子类的对象(由父类的引用handle)调用到的是父类的成员变量,运行时(动态)绑定针对的范畴只是对象的方法,而属性要采取静态绑定方法。
    2、执行p.method()时会先去调用子类的method方法执行,若子类没有则向上转型去父类中寻找。
    所以在向上转型的情况下,对象的方法可以找到子类,而对象的属性还是父类的属性。

    相关文章

      网友评论

        本文标题:Java之动态绑定与静态绑定

        本文链接:https://www.haomeiwen.com/subject/ehyhsttx.html