当前位置 : 主页 > 编程语言 > java >

【Java -- 虚拟器】方法分派模型 -- 静态分派、动态分派

来源:互联网 收集:自由互联 发布时间:2022-06-22
一、知识储备 1. 分派 定义:确定执行哪个方法 的过程 方法的执行不是取决于代码设置中的执行对象吗?为什么还要选择呢? 答:若 一个对象对应于多个方法 时,就需要进行选择了

一、知识储备

1. 分派
定义:确定执行哪个方法 的过程

方法的执行不是取决于代码设置中的执行对象吗?为什么还要选择呢?
答:若 一个对象对应于多个方法 时,就需要进行选择了
读者应该都想到了 Java中的特性:多态,即重写 & 重载。下面我会详细讲解。

分类:静态分派 & 动态分派。

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:会变化、在运行期才可知

}
}
  • 变量的静态类型 = 引用类型 :不会被改变、在编译器可知
  • 变量的动态类型 = 实例对象类型 :会变化、在运行期才可知

二、静态分派

1. 定义
根据 变量的静态类型 进行方法分派 的 行为

  • 即根据 变量的静态类型 确定执行哪个方法
  • 发生在编译期,所以不由 Java 虚拟机来执行

  • 2. 应用场景
    方法重载(OverLoad)

    3. 实例说明

    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!

    特别注意
    a. 变量的静态类型 发生变化 的情况
    可通过 强制类型转换 改变 变量的静态类型

    Human man = new Man();
    test.sayHello((Man)man);
    // 强制类型转换
    // 此时man的静态类型从 Human 变为 Man

    // 所以会调用sayHello()中参数为Man guy的方法,即sayHello(Man guy)

    b. 静态分派的优先级匹配问题

    三、动态分派

    1. 定义
    根据 变量的动态类型 进行方法分派 的 行为

    即根据 变量的动态类型 确定执行哪个方法

    2. 应用场景
    方法重写(Override)

    3. 实例说明

    // 定义类
    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 -- 虚拟器】方法分派模型 -- 静态分派、动态分派_静态类


    网友评论