動態綁定(又名後期綁定)
動態綁定是指編譯器在編譯階段不知道要調用哪個方法,直到運行時才能確定。讓我們用個例子來解釋。譬如我們有一個叫作’SuperClass’的父類,還有一個繼承它的子類’SubClass’。現在SuperClass引用也可以賦給SubClass類型的對象。如果SuperClass中有個someMethod()的方法,而子類也重寫了這個方法,那麼當調用SuperClass引用的這個方法的時候,編譯器不知道該調用父類還是子類的方法,因爲編譯器不知道對象到底是什麼類型,只有到運行時才知道這個引用指向什麼對象。
...
SuperClass superClass1 = new SuperClass();
SuperClass superClass2 = new SubClass();
...
superClass1.someMethod(); // SuperClass version is called
superClass2.someMethod(); // SubClass version is called
....
我們可以看到雖然對象引用superClass1和superClass2都是SuperClass類型的,但是在運行時它們分別指向SuperClass和SubClass類型的對象。
所以在編譯階段,編譯器不清楚調用引用的someMethod()到底是調用子類還是父類的該方法。
所以方法的動態綁定是基於實際的對象類型,而不是它們聲明的對象引用類型。
靜態綁定(又名前期綁定)
如果編譯器可以在編譯階段就完成綁定,就叫作靜態綁定或前期綁定。基本上實例方法都在運行時綁定,所有的靜態方法都在編譯時綁定,所以靜態方法是靜態綁定的。因爲靜態方法是屬於類的方法,可以通過類名來訪問(我們也應該使用類名來訪問靜態方法,而不是使用對象引用來訪問),所以要訪問它們就必須在編譯階段就使用編譯類型信息來進行綁定。這也就解釋了爲什麼靜態方法實際上不能被重寫。
類似的,訪問成員變量也是靜態綁定的,因爲Java不支持(實際上是不鼓勵)成員變量的多態行爲。下面看個例子:
class SuperClass{
...
public String someVariable = "Some Variable in SuperClass";
...
}
class SubClass extends SuperClass{
...
public String someVariable = "Some Variable in SubClass";
...
}
...
...
SuperClass superClass1 = new SuperClass();
SuperClass superClass2 = new SubClass();
System.out.println(superClass1.someVariable);
System.out.println(superClass2.someVariable);
...
輸出:
Some Variable in SuperClass
Some Variable in SuperClass
我們可以發現成員變量由對象引用聲明的類型決定,是由編譯器在編譯階段就知道的信息,所以是靜態綁定。另外一個靜態綁定的例子是私有的方法,因爲它們不會被繼承,編譯器在編譯階段就完成私有方法的綁定了。