您好,登錄后才能下訂單哦!
這篇文章主要介紹了怎么使用java JVM方法分派模型的相關知識,內容詳細易懂,操作簡單快捷,具有一定借鑒價值,相信大家閱讀完這篇怎么使用java JVM方法分派模型文章都會有所收獲,下面我們一起來看看吧。
定義:確定執行哪個方法 的過程
a. 疑問 有些讀者會問,方法的執行不是取決于代碼設置中的執行對象嗎?為什么還要選擇呢? b. 回答
若 一個對象對應于多個方法 時,就需要進行選擇了
讀者應該都想到了 Java
中的特性:多態,即重寫 & 重載。下面我會詳細講解。
分類:靜態分派 & 動態分派。下面我將詳細講解。
先看下面的代碼
public class Test { static abstract class Human { } static class Man extends Human { } static class Woman extends Human { } // 執行代碼 public static void main(String[] args) { Human man = new Man(); // 變量man的靜態類型 = 引用類型 = Human:不會被改變、在編譯器可知 // 變量man的動態類型 = 實例對象類型 = Man:會變化、在運行期才可知 } }
即:
變量的靜態類型 = 引用類型 :不會被改變、在編譯器可知
變量的動態類型 = 實例對象類型 :會變化、在運行期才可知
下面,我將詳細講解Java
中的分派類型:靜態分派 & 動態分派
定義 根據 變量的靜態類型 進行方法分派 的 行為
即根據 變量的靜態類型 確定執行哪個方法
發生在編譯期,所以不由 Java
虛擬機來執行
應用場景 方法重載(OverLoad
)
實例說明
public class Test { // 類定義 static abstract class Human { } // 繼承自抽象類Human static class Man extends Human { } static class Woman extends Human { } // 可供重載的方法 public void sayHello(Human guy) { System.out.println("hello,guy!"); } public void sayHello(Man guy) { System.out.println("hello gentleman!"); } public void sayHello(Woman guy) { System.out.println("hello lady!"); } // 測試代碼 public static void main(String[] args) { Human man = new Man(); Human woman = new Woman(); Test test = new Test(); test.sayHello(man); test.sayHello(woman); } } // 運行結果 hello,guy! hello,guy!
根據上述的講解,大家應該明白運行結果的原因:
方法重載(OverLoad
) = 靜態分派 = 根據 變量的靜態類型 確定執行(重載)哪個方法
所以上述的方法執行時,是根據變量(man
、woman
)的靜態類型(Human
)確定重載sayHello()
中參數為Human guy
的方法,即sayHello(Human guy)
特別注意
可通過 強制類型轉換 改變 變量的靜態類型
Human man = new Man(); test.sayHello((Man)man); // 強制類型轉換 // 此時man的靜態類型從 Human 變為 Man // 所以會調用sayHello()中參數為Man guy的方法,即sayHello(Man guy)
問題描述:
背景 現需要進行靜態分派
問題 程序中 沒有顯示指定 靜態類型
解決方案 程序會根據 靜態類型的優先級 從而選擇 優先的靜態類型進行方法分配。
實例說明
public class Overload { private static void sayHello(char arg){ System.out.println("hello char"); } private static void sayHello(Object arg){ System.out.println("hello Object"); } private static void sayHello(int arg){ System.out.println("hello int"); } private static void sayHello(long arg){ System.out.println("hello long"); } // 測試代碼 public static void main(String[] args) { sayHello('a'); } } // 運行結果 hello char
因為‘a’
是一個char
類型數據(即靜態類型是char
),所以會選擇參數類型為char
的重載方法。
若注釋掉sayHello(char arg)
方法,那么會輸出
hello int
因為‘a’
除了可代表字符串,還可代表數字97。因此當沒有最合適的sayHello(char arg)
方式進行重載時,會選擇第二合適(第二優先級)的方法重載,即 sayHello(int arg)
總結:當沒有最合適的方法進行重載時,會選優先級第二高的的方法進行重載,如此類推。
優先級順序為:
char>int>long>float>double>Character>Serializable>Object>...
其中...
為變長參數,將其視為一個數組元素。變長參數的重載優先級最低。
因為 char
轉型到 byte
或 short
的過程是不安全的,所以不會選擇參數類型為byte
或 short
的方法進行重載,故優先級列表里也沒有。
上面講解的主要是 基本數據類型的優先級匹配問題
若是引用類型,則根據 繼承關系 進行優先級匹配
注意只跟其編譯時類型(即靜態類型)相關
定義 根據 變量的動態類型 進行方法分派 的 行為
即根據 變量的動態類型 確定執行哪個方法
應用場景 方法重寫(Override
)
實例說明
// 定義類 class Human { public void sayHello(){ System.out.println("Human say hello"); } } // 繼承自 抽象類Human 并 重寫sayHello() class Man extends Human { @Override protected void sayHello() { System.out.println("man say hello"); } } class Woman extends Human { @Override protected void sayHello() { System.out.println("woman say hello"); } } // 測試代碼 public static void main(String[] args) { // 情況1 Human man = new man(); man.sayHello(); // 情況2 man = new Woman(); man.sayHello(); } } // 運行結果 man say hello woman say hello // 原因解析 // 1. 方法重寫(Override) = 動態分派 = 根據 變量的動態類型 確定執行(重寫)哪個方法 // 2. 對于情況1:根據變量(Man)的動態類型(man)確定調用man中的重寫方法sayHello() // 3. 對于情況2:根據變量(Man)的動態類型(woman)確定調用woman中的重寫方法sayHello()
特別注意
對于代碼中:
Human man = new Man(); man = new Woman(); man.sayHello(); // man稱為執行sayHello()方法的所有者,即接受者。
invokevirtual
指令執行的第一步 = 確定接受者的實際類型
invokevirtual
指令執行的第二步 = 將 常量池中 類方法符號引用 解析到不同的直接引用上
第二步即方法重寫(Override
)的本質
關于“怎么使用java JVM方法分派模型”這篇文章的內容就介紹到這里,感謝各位的閱讀!相信大家對“怎么使用java JVM方法分派模型”知識都有一定的了解,大家如果還想學習更多知識,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。