說明:這兩天遇到的一些Java方法指派的問題,結合自己書上看的,google的,還有撒迦教我的,做一個總結吧.望指正.
寫道 方法指派指的是虛擬機器如何確定應該執行哪個方法!
很多的內容可以參加撒迦的這篇博文 : http://rednaxelafx.iteye.com/blog/652719
我這篇裡很多概念的解釋都摘自上面的博文,所以,我就不一一指出啦.在此感謝撒迦的協助.
還有一些講解(包括代碼)來自 <深入JAVA虛擬機器-jvm進階特性與最佳實務>,很好一本書,推薦對jvm有興趣的同學購買
另外 http://hllvm.group.iteye.com/group/topic/27064 這個文章也可能協助大家對方法指派有所瞭解. 1 靜態指派
對於這個靜態指派,撒迦很喜歡叫做非虛方法指派(當然按照他自己的說法就是:我不喜歡叫靜態指派).
首先,解釋一下什麼叫虛方法.虛方法的概念有點難說,不過把什麼是非虛方法說明一下,其他的就是虛方法啦.哈哈 非虛方法是所有的類方法(也就是申明為static的方法) + 所有聲明為final或private的執行個體方法.
由於非虛方法不能被override,所以自然也不會產生子類複寫的多態效果.這樣的話,方法被調用的入口只可能是一個.而且編譯器可知.也就是說,jvm需要執行哪個方法是在編譯器就已經確定.且在運行期不會變化.很具體的例子就是方法的重載.
看如下例子,摘自 <深入JAVA虛擬機器-jvm進階特性與最佳實務>
Java代碼 public class StaticDispatch { static abstract class Human{ } static class Man extends Human{ } static class Woman extends Human{ } public void sayHello(Human human){ System.out.println("human say hello"); } public void sayHello(Man man){ System.out.println("man say hello"); } public void sayHello(Woman woman){ System.out.println("woman say hello"); } /** * @param args */ public static void main(String[] args) { Human man = new Man(); Human woman = new Woman(); StaticDispatch sd = new StaticDispatch(); sd.sayHello(man); sd.sayHello(woman); } }
最後的輸出是 console 寫道 human say hello
human say hello
這個就是很典型的靜態指派.看這段代碼
Human man = new Man();
Human woman = new Woman();
其中的Human 稱為變數的靜態類型,而後面的Man稱為變數的實際類型. 靜態類型是在編譯器可見的,而動態類型必須在運行期才知道.再分析這段調用的方法
StaticDispatch sd = new StaticDispatch();
sd.sayHello(man);
sd.sayHello(woman);
我們看到,調用方法的接受者是確定的,都是sd.在靜態指派中,jvm如何確定具體調用哪個目標方法就完全取決於傳入參數的數量和資料類型.而且是根據資料的靜態類型..正因為如此,這兩個sayHello方法,最後都調用了public void sayHello(Human human);方法.
但是,仔細看會發現,我舉的這個例子,雖然確實是通過靜態指派的,但是具體的方法卻是虛方法..也就是說, 虛方法也可能是被靜態指派的.特別注意,重載就是通過靜態指派的
其實非虛方法的靜態指派是完全合理的,後面會再舉一個例子,來確定只要是非虛方法,肯定是通過靜態指派的.
本節最後的問題是 寫道 Java語言中方法重載採用靜態指派是JVM規範規定的還是語言層級的規定?
這個問題曾經讓我有過困惑.因為上面這個重載的例子中, Java代碼 sd.sayHello(man); sd.sayHello(woman);
這兩個sayHello方法都是用invokevirtual 指令(關於這個指令,後面會開專門的一節說明)的,那麼其實完全可以採用動態指派,根據man 和 woman 的實際類型來決定調用哪個方法.但是實際上jvm缺沒這麼做.一直等我在仔細看了Java語言"單指派還是多指派"這個內容以後,才有了答案.下面會專門開一節說這個單指派和多指派.這個問題也在後面解答.
2 動態指派
可以說,動態方法指派是Java實現多態的一個重要基礎.因為,它是Java多態之一----重寫的基礎.看下面的代碼,,摘自 <深入JAVA虛擬機器-jvm進階特性與最佳實務> Java代碼 public class DynamicDispatch { static abstract class Human{ protected abstract void sayHello(); } static class Man extends Human{ @Override