[读书笔记]Java之动态分派

以下内容来自周志明的《深入理解Java虚拟机》。

前一篇说了静态分派和重载有关,现在的动态分派就和覆盖Override有关了。

先看代码:

public class DynamicDispatch {
    static abstract class Human {
        protected abstract void sayHello();
    }

    static class Man extends Human {
        @Override
        protected void sayHello() {
            System.out.println("man");
        }
    }

    static class WoMan extends Human {
        @Override
        protected void sayHello() {
            System.out.println("woman");
        }
    }

    public static void main(String[] args) {
        Human man = new Man();
        Human woman = new WoMan();
        man.sayHello();
        woman.sayHello();
        man = new WoMan();
        man.sayHello();
    }
}

结果输出:

man
woman
woman

这里不再根据静态类型来决定,因为静态类型同样都是Human的两个变量man和woman在调用sayHello()方法时执行了不同的行为,因为这两个变量的实际类型不同。

运行期根据实际类型其确定方法执行版本的分派过程称为动态分派。

原书中作者使用了javap命令输出了这段代码的字节码来分析为何是运行时的不同,还讲解了invokevirtual指令的解析步骤,这里就不赘述了。

单分派和多分派

public class Dispatch {
    static class QQ {
    }

    static class _360 {
    }

    public static class Father {
        public void hardChoice(QQ args) {
            System.out.println("father choose qq");
        }

        public void hardChoice(_360 args) {
            System.out.println("father choose 360");
        }
    }

    public static class Son extends Father {
        public void hardChoice(QQ args) {
            System.out.println("son choose qq");
        }

        public void hardChoice(_360 args) {
            System.out.println("son choose 360");
        }
    }

    public static void main(String[] args) {
        Father father = new Father();
        Father son = new Son();
        father.hardChoice(new _360());
        son.hardChoice(new QQ());
    }
}
//输出
father choose 360
son choose qq

java语言的静态分派属于多分派类型,在编译阶段,选择目标方法的依据有两点:

1. 静态类型是Father还是Son

2. 方法参数是QQ还是360

动态分派属于单分派类型,在运行时,执行son.hardChoice(new QQ())这句代码时,由于编译器已经决定目标方法的签名必须为harChoice(QQ),虚拟机不会关系传递过来的参数QQ到底是“腾讯QQ”还是"奇瑞QQ",因为这时参数的静态类型和实际类型都对方法的选择不会构成影响,唯一可以影响虚拟机选择的因为只有方法的接受者的类型是Father还是Son。

再重申一下:静态分派在编译器就完成了,动态分派是运行时才进行的。所以Father son=new Son()这句,虽然静态类型是Father,但是运行后的实际类型是Son,所以son.hardChoice执行的是Son类里的方法而不是Father类里的。

原文地址:https://www.cnblogs.com/yasire/p/5426378.html