为了知道静态绑定和动态绑定的区别,我们先了解一下什么是绑定。绑定就是指引用与实际代码之间的关联,比如说,当你引用一个变量的时候是由定义这个变量的代码确定的。同样的当你调用一个方法的时候,它会与这个方法的定义关联起来。在Java里面方法绑定有两种方式,一种叫静态绑定,一种叫动态绑定。当一个方法被调用的时候程序实际的执行和对象的创建有可能在编译期确定,也可能在运行期。就像名字所说,静态绑定有着静态的本质,因此它发生在编译期里,就好比根据编译的结果你可以在代码里清楚知道某方法的调用对应的源码在哪个class文件里面。
另一方面,当JVM开始执行你的程序时动态绑定发生在运行期间。方法的调用被取决于实际的对象,这些对象的信息在编译期里是不能得到的,因为对象的创建在运行期。因为在程序生命周期发生较晚,它也叫后期绑定。
那么他们最基本的不同就是一个使用变量引用类型发生在编译期,一个使用实际对象发生在运行期。
前期绑定 vs 后期绑定
关于静态绑定和动态绑定的区别有很多观点,但是最重要的还是要看JVM怎么去使用。你是否有想过当有多个同名的方法的时候JVM是怎么确定要去调用哪个的?如果你知道方法重载(overloading)或者方法重写(overriding)的话你应该知道方法重名是怎么回事。JVM会根据静态或动态绑定去寻找对应的方法。
静态和绑定的例子
在以下程序,你可以看到即使使用了静态绑定,虚拟方法(virtual methods)并没有绑定在编译期,因为按我们想法会出现父类是会被调用的,但是事实上并不是。由于子类的方法被调用证明真实的对象在运行期被使用,因此动态绑定一般用于绑定虚拟方法。
public class Main {
public static void main(String[] args) {
// An example of static and dynamic binding in Java
Insurance current = new CarInsurance();
// dynamic binding based upon object
int premium = current.premium();
// static binding based upon class
String category = current.category();
System.out.println("premium : " + premium);
System.out.println("category : " + category);
}
class Insurance{
public static final int LOW = 100;
public int premium(){
return LOW;
}
public static String category(){
return "Insurance";
}
}
class CarInsurance extends Insurance{
public static final int HIGH = 200;
public int premium(){
return HIGH;
}
public static String category(){
return "Car Insurance";
}
}
//Output premium : 200
//category : Insurance
}
你可以看到当调用premium()方法的时候是执行的是子类的方法,而当调用cateogry()方法的时候是执行父类的方法。这是因为premium()是虚拟方法并且使用的是前期绑定来处理,而category()方法是一个静态方法,在编译期使用类名做静态绑定来处理。
前期和后期绑定的区别总结
现在你知道和明白方法的调用是如何绑定的和静态和动态的绑定是怎样工作的(说的那么简单我还真没看明白),让我们来回顾一下他们之间的一些重要的、关键的不同:
静态绑定发生在编译期而动态绑定发生在运行期
因为静态绑定发生在程序生命周期较早阶段,它也叫前期绑定。同样动态绑定发生在程序实际运行中,所以也叫后期绑定。
静态绑定一般用于方法重载,而动态绑定一般用于方法重写。
同样,静态绑定可以用于私有的(private)、静态的(static)和终态的(final)方法,因为他们不能被重写和所有虚拟方法用动态绑定来解决。
真实的对象不能用于静态绑定,相反,类型信息比如变量的类型可以用于本地的方法。另一方面,动态绑定用一个真是的对象去找到那个真正的方法的。
这里有个很好的练习是基于静态和动态绑定的,答案是?
triky Java Interview Questions in Java.png