深入理解JVM-方法调用(含重写和重载的本质)

网站优化

  对代码负责,开发过程中允许有技术债务,但是技术债务一定要偿还,如果不偿还技术债务,就不是技术上的问题,而是道德上的问题,坚持学习,让学习成为一种习惯,希望更多喜欢技术的人,让编程除了作为生存的基本技能之外,更多的是作为生活的一部分,一种习惯,我们结伴而行,今天我们学习JVM中的方法调用,很多人都知道重写和重载,但是不了解重写和重载的本质是什么,今天我们就深入的了解,方法在什么时候确定调用的方法地址的

  解析

  方法的调用分为解析和分派,解析是针对非虚方法,在编译期就已经确定了,并且是不可变的,分派是编译期不可知,运行期确定

  非虚方法包括静态方法、构造函数、私有方法、父类中的方法,这些方法在类加载阶段就会将符号引用转换为直接引用

  静态分派

  静态分派是指所有依赖静态类型确定方法的版本(就是调用哪个方法),比较典型的就是方法重载,确定重载方法的过程,就是静态分派的过程,本质是根据参数的静态类型确定调用哪个方法而不是根据参数的实际类型确定调用哪个方法

  Human man = new Man()为例, Human为静态类型,Man为实际类型,静态类型在编译期就已经确定了,是不可变的,重载核心的一点就是根据静态类型的参数类型确定的,而不是根据实际的参数类型确定,注释掉参数为Human类型的方法,会发现编译期报错,因为不存在静态类型是Human的方法

  通过jclasslib查看指令发现编译期已经确定

  方法版本的确定可以通过参数的可以自动转型确定,自动转型的前提是实参范围小于形参范围(想想设计原则的里氏替换原则),找到最接近的参数类型对应的方法作为最终调用的方法,意思就是如果没有参数为Man类型的方法,但是存在Human类型的方法,会匹配到参数为Human类型的方法

  3.2.4.3动态分派

  动态分配指根据方法实际类型参数确定方法调用,比较典型的是方法重写,下面的输出结果是什么呢?

  答案是:son:0, son:4, 51,分析一下为什么会得出这个结果,首先创建子类势力,会初始化父类构造,age=51,因为子类重写了父类的方法,所以第一次父类构造中的getAge方法是虚方法调用,实际是执行的子类的方法,因为子类还没有执行构造,age是子类的age此时初始为0,所以打印son:0;接着再执行子类构造为age赋值为4,再调用子类的getAge方法,打印son:4,最后打印son.age,这个age是父类的age,重写只存在方法间的重写,字段在编译期就已经确定了,Father是静态类型,所以访问的是Father的age

  3.2.4.4单分派与多分派

  单分派和多分派是基于多少方法的宗量区分的,方法的接收者和方法参数统称宗量,静态多宗量,动态单宗量,静态多宗量指在编译期就已经确定了一个父类创建了多个子类的实例,然后调用几个子类重写的方法,动态单分派指在执行方法的时候就已经确定目标方法,没有因素能能影响方法的选择

  3.2.4.5 jvm动态分派实现

  JVM动态分派通过维护父类和子类的虚方法表优化实际方法真实地址,子类没有重写父类的方法,子类虚方法表中真实地址指向父类方法真实地址,子类重写了父类的方法,子类方法在虚方法表指向实际方法地址,Father和Son都未重写Object方法,所以虚方法都指向Object虚方法对应真实地址

标签: 网站优化