首頁  >  文章  >  Java  >  Java JVM 方法分派模型的使用方式

Java JVM 方法分派模型的使用方式

WBOY
WBOY轉載
2023-04-21 10:49:071339瀏覽

1. 知識儲備

1.1 分派

  • 定義:決定執行哪個方法的過程

  • # a. 疑問 有些讀者會問,方法的執行不是取決於程式碼設定中的執行物件嗎?為什麼還要選擇呢?

    b. 回答
  • 若一個物件對應於多個方法時,就需要進行選擇了

## 讀者應該都想到了

Java

中的特性:多型,即重寫& 重載。下面我會詳細講解。

  • 分類:靜態分派 & 動態分派。下面我將詳細講解。

  • 1.2 變數的靜態型別& 動態型別

    先看下面的程式碼
  • 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
  • #中的分派類型:靜態分派& 動態分派

    2. 靜態分派
  • #定義根據變數的靜態型別進行方法分派的行為

  • #即根據變數的靜態型別決定執行哪個方法

    #發生在編譯期,所以不由
  • 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)

  • 特別注意

    a. 變數的靜態型別改變的情況
可透過
    強制型別轉換
  • 改變變數的靜態型別

    Human man = new Man(); 
    test.sayHello((Man)man); 
    // 强制类型转换
    // 此时man的静态类型从 Human 变为 Man
    // 所以会调用sayHello()中参数为Man guy的方法,即sayHello(Man guy)

    b. 靜態分派的優先權匹配問題
  • #問題描述:
背景現需要進行靜態分派

問題程式中沒有顯示指定靜態類型解決方案程序會根據靜態類型的優先權從而選擇優先的靜態類型進行方法分配。

實例說明

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的重載方法。 <strong></strong>若註解掉sayHello(char arg)方法,那麼會輸出

hello int
因為<strong>‘a’</strong>除了可代表字串,還可代表數字97。因此當沒有最合適的

sayHello(char arg)

方式進行重載時,會選擇第二合適(第二優先級)的方法重載,即

sayHello(int arg)

#總結:當沒有最適合的方法進行重載時,會選取優先順序第二高的方法進行重載,如此類推。

優先權順序為:char>int>long>float>double>Character>Serializable>Object>...其中#...為變長參數,將其視為陣列元素。變長參數的重載優先權最低。

因為

char

轉型到
    byte
  • short 的過程是不安全的,所以不會選擇參數型別為byte

  • short
  • 的方法進行重載,故優先權清單裡也沒有。

    特別注意

上面講解的主要是

基本資料型別

的優先權比對問題

  • 若是引用類型,則根據

    繼承關係

    進行優先權匹配

注意只跟其編譯時類型(即靜態類型)相關
  • 3. 動態分派

    定義根據變數的動態型別進行方法分派的行為
  • 即根據變數的動態型別決定執行哪個方法

應用程式場景方法重寫(

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)的本質

4. 二者差異

Java JVM 方法分派模型的使用方式

以上是Java JVM 方法分派模型的使用方式的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:yisu.com。如有侵權,請聯絡admin@php.cn刪除