方法解析

Class文件的编译过程中不包含传统编译中的连接步骤,一切方法调用在Class文件里面存储的都只是符号引用,而不是方法在实际运行时内存布局中的入口地址。这个特性给Java带来了更强大的动态扩展能力,使得可以在类运行期间才能确定某些目标方法的直接引用,称为动态连接,也有一部分方法的符号引用在类加载阶段或第一次使用时转化为直接引用,这种转化称为静态解析

静态解析成立的前提是:方法在程序真正执行前就有一个可确定的调用版本,并且这个方法的调用版本在运行期是不可改变的。换句话说,调用目标在编译器进行编译时就必须确定下来,这类方法的调用称为解析。

在Java语言中,符合“编译器可知,运行期不可变”这个要求的方法主要有静态方法和私有方法两大类,前者与类型直接关联,后者在外部不可被访问,这两种方法都不可能通过继承或别的方式重写出其他的版本,因此它们都适合在类加载阶段进行解析。

解析调用一定是个静态过程,在编译期间就完全确定,在类加载的解析阶段就会把涉及的符号引用转化为可确定的直接引用,不会延迟到运行期再去完成。而分派调用可能是静态的也可能是动态的,根据分派依据的宗量数(方法的调用者和方法的参数统称为方法的宗量)又可分为单分派和多分派。两类分派方式两两组合便构成了四种分派情况:

  • 静态单分派
  • 静态多分派
  • 动态单分派
  • 动态多分派

静态分派

所有依赖静态类型来定位方法执行版本的分派动作,都称为静态分派,静态分派的最典型应用就是多态性中的方法重载。

静态分派发生在编译阶段,因此确定静态分配的动作实际上不是由虚拟机来执行的。下面通过一段方法重载的示例程序来更清晰地说明这种分派机制:

class Human{}
class Man extends Human{}
class Woman extends Human{}
public class StaticPai{public void say(Human hum){System.out.println("I am human");}public void say(Man hum){System.out.println("I am man");}public void say(Woman hum){System.out.println("I am woman");}public static void main(String[] args){Human man = new Man();Human woman = new Woman();StaticPai sp = new StaticPai();sp.say(man);sp.say(woman);}
}

上面代码的执行结果如下:

  I am human I am human

以上结果的得出应该不难分析。在分析为什么会选择参数类型为Human的重载方法去执行之前,先看如下代码:

Human man = new Man();

我们把上面代码中的“Human”称为变量的静态类型,后面的“Man”称为变量的实际类型。静态类型和实际类型在程序中都可以发生一些变化,区别是静态类型的变化仅仅在使用时发生,变量本身的静态类型不会被改变,并且最终的静态类型是在编译期可知的,而实际类型变化的结果在运行期才可确定。

回到上面的代码分析中,在调用say()方法时,方法的调用者(回忆上面关于宗量的定义,方法的调用者属于宗量)都为sp的前提下,使用哪个重载版本,完全取决于传入参数的数量和数据类型(方法的参数也是数据宗量)。代码中刻意定义了两个静态类型相同、实际类型不同的变量,可见编译器(不是虚拟机,因为如果是根据静态类型做出的判断,那么在编译期就确定了)在重载时是通过参数的静态类型而不是实际类型作为判定依据的。并且静态类型是编译期可知的,所以在编译阶段,Javac编译器就根据参数的静态类型决定使用哪个重载版本。这就是静态分派最典型的应用。

动态分派

根据变量的实际类型来分派方法的执行版本的。而实际类型的确定需要在程序运行时才能确定下来,这种在运行期根据实际类型确定方法执行版本的分派过程称为动态分派。

动态分派与多态性的另一个重要体现——方法覆写有着很紧密的关系。向上转型后调用子类覆写的方法便是一个很好地说明动态分派的例子。这种情况很常见,因此这里不再用示例程序进行分析。很显然,在判断执行父类中的方法还是子类中覆盖的方法时,如果用静态类型来判断,那么无论怎么进行向上转型,都只会调用父类中的方法,但实际情况是,根据对父类实例化的子类的不同,调用的是不同子类中覆写的方法,很明显,这里是要根据变量的实际类型来分派方法的执行版本的。而实际类型的确定需要在程序运行时才能确定下来,这种在运行期根据实际类型确定方法执行版本的分派过程称为动态分派。

单分派和多分派

方法的接受者(亦即方法的调用者)与方法的参数统称为方法的宗量。单分派是根据一个宗量对目标方法进行选择,多分派是根据多个宗量对目标方法进行选择。

  • 方法重载属于静态多分派
  • 方法重写属于动态单分派

们可以总结如下:目前的Java语言是一门静态多分派、动态单分派的语言。

多态机制遵循的原则概括为:当超类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法,但是它仍然要根据继承链中方法调用的优先级来确认方法,该优先级为:this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。


THE END.

Java静态多态和动态多态相关推荐

  1. C++知识点 多态、静态多态、动态多态

    多态 有了继承才有多态的概念,首先说一下继承. 继承的概念是派生类可以调用基类的成员.常举的例子,动物是基类,它拥有所有动物共有的一些特征和方法.它会衍生出猫的类,狗的类,派生出的类除了有动物公共的特 ...

  2. C++多态——静态多态与动态多态

    多态 : 顾名思义,多态就是多种形态,也就是对不同对象发送同一个消息,不同对象会做出不同的响应. 并且多态分为静态多态和动态多态. 静态多态就是在系统编译期间就可以确定程序执行到这里将要执行哪个函数, ...

  3. C++ 多态(动态多态)

    本文结合黑马程序员.C语言中文网以及<C++ Primer>对多态进行了总结 多态的基本概念 多态是C++面向对象三大特性之一. 多态分为两类 静态多态: 函数重载 和 运算符重载属于静态 ...

  4. C++_类和对象_C++多态_多态的基本语法_静态多态_动态多态_虚函数---C++语言工作笔记069

    然后我们再来看看C++中的多态,这里还要注意一点,就是在C++中是可以用多继承的, 但是java.不行,只能实现多个接口,不能继承多个类.这让c++会更加灵活一点. 可以看到,上面说了,在c++中,分 ...

  5. C++静态多态与动态多态

    静态多态(编译期/早绑定) 函数重载 class A {public:void do(int a);void do(int a, int b); }; 动态多态(运行期期/晚绑定) •虚函数:用 vi ...

  6. java静态代理与动态代理简单分析

    原创作品,可以转载,但是请标注出处地址http://www.cnblogs.com/V1haoge/p/5860749.html 1.动态代理(Dynamic Proxy) 代理分为静态代理和动态代理 ...

  7. java静态代理与动态代理

    2019独角兽企业重金招聘Python工程师标准>>> 代理模式是java常见的设计模式.其目的是为其他对象提供一个代理以控制对某个真实对象的访问.通过代理类这一中间层,有效控制对真 ...

  8. Java静态代理、动态代理与CGLib代理

    java的动态代理举足轻重,它同反射原理一直是许多框架的底层实现.今天唠一下. 一.代理模式 代理模式是一种设计模式,提供了对目标对象额外的访问方式,即通过代理对象访问目标对象,这样可以在不修改原目标 ...

  9. Java静态代理、动态代理以及CGLIB动态代理

    代理模式是java中最常用的设计模式之一,尤其是在spring框架中广泛应用.对于java的代理模式,一般可分为:静态代理.动态代理.以及CGLIB实现动态代理. 对于上述三种代理模式,分别进行说明. ...

最新文章

  1. 递归实现牛顿法求整数平方根(原理: 给一个初始值(比如X1 = a/2)迭代求a的平方根,设定一个误差限,不断逼近a X1 = a/2 X2 = (X1+a/X1)/
  2. T-SQL游标学习总结
  3. 性能测试(03)-JDBC Request
  4. 帝国扩展变量是哪个php,帝国CMS后台系统设置里面的扩展变量是干什么的?
  5. 〈转贴〉如何解决 Windows XP 中的硬件和软件驱动程序问题
  6. java 设计模式 prototype_Java设计模式之Prototype原型模式
  7. iOS利用SDWebImage实现缓存的计算与清理
  8. 3 - Spring AOP
  9. uniapp---使用浏览器_Android真机_Iphone真机实时展示uniapp_一次开发_小程序_Android_IOS_快应用通用工作笔记003
  10. JNA调用DLL函数遇到的几个问题
  11. Redis 外部访问设置
  12. Java工程师必备资料,整合1G多jar包,网速慢也没关系,关注获取更多资源
  13. 数字图像处理理论课件(清华大学计算机科学与技术系)
  14. python 解压zip rar 7z文件
  15. Golang 1.16新特性-embed包及其使用
  16. Android 日历自定义文本
  17. Greenplum 添加mirror步骤
  18. crt设置自动保存日志的方法
  19. 云服务器跟弹性云主机一样吗,什么是弹性云主机
  20. QT报错:Makefile.Debug : moc_xxx.cpp error1

热门文章

  1. 路由器芯片方案、第三方固件秘密全在这里了
  2. python-turtle入门
  3. Exel将一张表拆分为多张表格以及安装方方格子
  4. 什么是专利权?专利有多少种类?
  5. 2022-2028年全球及中国羊皮避孕套行业发展现状调研及投资前景分析
  6. php编程狼和兔子山洞,一天,一只兔子在山洞前写论文, 一只狼走了过来,问:“兔子啊,你在干什么?” 兔。。。...
  7. 如何做好网站策划方案
  8. [1153]mysql中between的边界范围
  9. Architectural Design
  10. 2020年熔化焊接与热切割模拟考试系统及熔化焊接与热切割考试试题