Java静态绑定&动态绑定

1:理解Java中方法调用的过程

1)编译器查看对象的生命类型和方法名,假设调用 x.f(param),且隐式参数 x 生命为 C类的对象,因为可能存在多个方法名为 f 的方法 eg:f(int) , f(double) 编译器会列举出 C 类中名为 f 的方法和其父类中访问属性为 public 且名为 f 的方法(因为父类的私有方法不可访问)

2)重载解析:编译器根据 方法的参数类型 选择合适的方法调用,因为存在类型转换(int可以转换成Double )这个具体的寻找方法的过程可能很复杂,如果编译器没有找到跟参数类型匹配的方法,或者有多个与参数类型匹配的方法 编译期间会报错。

3)上面阶段2 编译器已经获取了需要调用方法的 方法名字和参数,下面开始进行绑定:

1:如果方法是  private 方法,static方法,final方法,或者构造器  编译器就可以准确知道应该调用那个方法,我们将这种调用方式成为 静态绑定 (static binding)    =》 因为 statci 和 final 方法不能被继承,private声明的方法和成员变量不能被子类继承,所有的private方法都被隐式的指定为final的(由此我们也可以知道:将方法声明为final类型的一是为了防止方法被覆盖,二是为了有效的关闭java中的动态绑定)

2:如果方法不是上面的这4种情况,编译器会进行动态绑定  

4) 当程序运行时,并且是采用动态绑定调用方法时,JVM 会调用与 X 所引用对象的实际类型最合适的那个类方法,假设X 类型是D类型,它是C的子类 如果 D 类中定义了 f(string) 方法,则会直接调用,不会去 C中查找   =》 为了避免每次调用方法都进行查找,虚拟机会预先为每个类 生成对应的方法表  , 方法表中记录了 所有方法的签名和实际调用的方法

2:动态绑定:

  • 特性:无需对现存的代码进行修改,就可以对程序进行扩展。 eg:增加一个新类 Executive 并且变量 e能引用到这个类的对象 不需要对 e.getSalary() 代码进行重新编译,就能调用到 Executive.getSalary()方法

3:java 动态绑定在属性上 和 方法上的不同


1.Java的方法调用过程
编译器查看对象的声明类型和方法名(对象变量的声明类型)。通过声明类型找到方法列表。
编译器查看调用方法时提供的参数类型。
如果方法是private、static、final或者构造器,编译器就可以确定调用那个方法。这是静态绑定。
如果不是上述情况,就要使用运行时(动态)绑定。

在程序运行时,采用动态绑定意味着:虚拟机将调用对象实际类型所限定的方法。

2.运行时(动态)绑定的过程

虚拟机提取对象的实际类型的方法表;
虚拟机搜索方法签名;
调用方法。
注意,这里说的是对象的实际类型。即在多态的情况下,虚拟机可以找到所运行对象的真正类型。

3.在向上转型情况下的动态绑定示例
Java代码

public class Person{
public void method() {
System.out.println(“父类方法,对象类型:” + this.getClass());
}
} 

public class Man extends Person{
public static void main(String[] args) {
Person sample = new Man();   //向上转型
sample.method();
}
}


结果1:
父类方法,对象类型:class sample.Person

这个结果没有疑问,声明的是父类的引用(句柄),但准确的调用了子类的对象,调用method,在子类中没有该方法,所以去父类中寻找到并调用之。


现在修改子类,重写(override)method方法。

public class Son extends Father {
public void method() {
System.out.println(“子类方法,对象类型:” + this.getClass());
}

public static void main(String[] args) {   
   Father sample = new Son();//向上转型   
   sample.method();   
}   


结果2:
子类方法,对象类型:class samples.Son

这个结果也是意料之中的。调用method时,在子类中寻找到了该方法,所以直接调用之。

4.静态绑定成员变量


在处理Java类中的成员变量时,并不是采用运行时绑定,而是一般意义上的静态绑定。所以在向上转型的情况下,对象的方法可以“找到”子类,而对象的属性还是父类的属性。



总结:属性不能被虚拟调用,因为他不能被重写,而方法可以,它被对象的真实类型调用。

猜你喜欢

转载自blog.csdn.net/never_compromise2580/article/details/82873762