正文
Java的三大特性,即封装、继承、多态。最能体现重载和重新的特征是在三大特性中的多态体现的。而在多态的实现的过程中,分派的调用过程是Java多态的特征的一些基本的体现。下面简单的说明一下什么是静态分派和动态分派。
静态分派:所有依赖静态类型来决定执行版本的分派为静态分派。
下面看一个例子:
执行的结果如下:
Human man = new Man(); 这行代码中Human称为变量的静态类型,
或者是外观类型。
后面的Man类型称为实际类型或者叫做运行时类型。
静态类型和实际类型在程序中都有可能发生变化。区别是静态类型的变化仅仅发生在使用的时候,变量自身的静态类型是不会发生变化的,并且最终的静态类型是在编译期间是可以知道的。而实际类型是在运行期间才能确定,编译器在编译期间是不知道一个对象的类型是什么的。而静态分派就是根据静态类型来执行的,静态分派最典型的代表就是方法重载。
静态分派发生在编译阶段,因此静态分派动作实际上不是由虚拟机来执行的。
动态分派:它是Java语言多态性的另一种体现--方法重写
运行结果如下:
从上面运行的结果可以看出,调用方法的选择不可能再根据静态类型来决定的,因为静态类型同样都是Human的类型。导致运行结果不一样是因为实际类型的不同,那么JVM是通过什么样的方式通过实际类型找到执行版本的呢?我们下面的图片:
可以看到,实际上采用的是invokevirtual字节码命令来实现的,而invokevirtual这个命令是在运行期间确定接收者的实际类型,所以两次调用的结果是不同的。也就是说重写的本质是:在运行期间,JVM采用invokevirtual的命令确定接受者的实际类型,而在解析常量池中到方法引用后,还要根据接受者的实际类型选择方法的版本。
把这种在运行期间根据实际类型确定执行方法的版本的分派过程称为动态分派。
单分派和多分派:静态分派属于多分派类型,而动态分派属于单分派。所以java语言是静态多分派,动态单分派的语言。
重载是静态多分派实现的,重写是动态单分派实现的。