04 JVM是如何执行方法调用的(上)

Wesley13
• 阅读 377

重载和重写

重载:同一个类中定义名字相同的方法,但是参数类型或者参数个数必须不同。

重载的方法在编译过程中就可完成识别。具体到每一个方法的调用,Java 编译器会根据所传入参数的生命类型来选取重载方法。选取的过程分以下三个阶段: 1:在不考虑对基本类型自动装拆箱,以及可变长参数的情况下选取重载方法。 2:如果第 1 个阶段未找到,那么在允许自动装拆箱,但是不允许可变长参数的情况下选出重载方法。 3:如果第 2 个阶段未找到,那么在允许自动装拆箱以及允许可变长参数的情况下选出重载方法。

如果 Java 编译器在同一个阶段中找到了多个适配的方法,那么它会在其中选择一个最为贴切的,而决定贴切程度的一个关键就是形式参数类型的继承关系。

重写:子类定义了跟父类方法同名,参数类型一致的方法,就叫做子类重写了父类方法。

Java 是一门面向对象的变成语言,它的一个重要的特性就是多态。而方法的重写,正是多态最重要的一种体现方式。

JVM 的静态绑定和动态绑定

Java 虚拟机识别方法的关键在于类型,方法名以及方法的描述符。方法的描述符是由方法的参数类型以及返回类型所构成的。在同一个类中,如果出现多个名字相同,方法描述符也相同的方法,那么 Java 虚拟机会在类的验证阶段报错。

由此观之,Java 虚拟机与 Java 语言不通,它并不限制名字与参数类型相同,但返回类型不同的方法出现在同一个类中。对于调用这些方法的字节码来说,由于字节码附带的方法描述符包含了返回类型,因此 Java 虚拟机能够准确地识别目标方法。所以,Java 虚拟机判定重写的依据是:方法名,参数类型以及返回类型都相同。

由于重载方法的区分在编译阶段已经完成,我们可以认为 Java 虚拟机不存在重载这一概念。因此,重载也被称为静态绑定,或者叫编译时多态。而重写则被称为动态绑定。

Java 虚拟机中的静态绑定指的是解析时便能够直接识别目标方法的情况,动态绑定指的是需要在运行过程中根据调用者的动态类型来识别目标方法的情况。

Java 字节码中与调用相关的指令有五种。 1:invokestatic,用于调用静态方法 2:invokespecial,用于调用私有实例方法,构造器,以及实用 super 关键字调用父类的实例方法或构造器,以及所实现接口的默认方法。 3:invokevirtual,用于调用非私有实例方法。 4:invokeinterface,用于调用接口方法。 5:invokedynamic,用于调用动态方法。

调用指令的符号引用

编译过程中,我们并不知道目标方法的具体内存地址。因此,Java 编译器会暂时用符号引用来表示该目标的方法。这一符号引用包括目标方法所在的类或接口的名字,以及目标方法的方法名和方法描述符。

符号引用存储在 class 文件的常量池之中。根据目标方法是否为接口方法,这些引用分为:接口符号引用和非接口符号引用。

在执行使用了符号引用的字节码钱,Java 虚拟机需要解析这些符号引用,并替换为实际引用。

对于非接口符号引用,假定该符号引用所指向的类为 C,则 Java 虚拟机会按照如下步骤进行查找: 1:在 C 中查找符号名字及描述符的方法。 2:如果没找到,在 C 的父类总继续搜索,直至 Object 类。 3:如果没找到,在 C 所直接实现或间接实现的接口中搜索,搜索的目标方法必须是非私有非静态的。并且,如果目标方法在间接实现的接口中,则需满足 C 与该接口之间没有其他符合条件的目标方法。如果有多个符合条件的目标方法,则任意返回其中一个。

对于接口符号引用,假定该符号引用所指向的接口为 I,则 Java 虚拟机会按照如下步骤进行查找: 1:在 I 中查找符合名字及描述符的方法。 2:如果没有找到,在 Object 类中的共有实例方法中搜索。 3:如果没有找到,则在 I 的超接口中搜索,搜索的目标方法必须是非私有非静态的。并且,如果目标方法在间接实现的接口中,则需满足 C 与该接口之间没有其他符合条件的目标方法。如果有多个符合条件的目标方法,则任意返回其中一个。

通过上述步骤,符号引用会被解析成实际引用。对于可以静态绑定的方法调用而言,实际引用是一个指向方法的指针。对于需要动态绑定的方法调用而言,实际引用则是一个方法表的索引。

问答

Q:什么是直接实现?什么是间接实现?

C implements Interface1,Interface1 extends Interface2,C直接实现Interface1,间接实现Interface2

Q:public final 或 public static final 的方法,是不是在 虚拟机中解析为静态绑定的

静态方法都是静态绑定。调用的目标方法是public final 的话,HotSpot虚拟机也会静态绑定。但这属于优化,其它虚拟机不一定这么做。

Q:请问子类可以调用父类的静态方法是什么意思

class Foo { static void m(){} } class Bar extends Foo{} Bar.m();

Q:重载方法选取阶段中:那么在允许自动装拆箱,但是不允许可变长参数的情况下选出重载方法。举例演示

public void method(String str){ ... } public void method(Object obj){ ... }

method(null);一直调用的是string参数的方法

总结

本文创作灵感来源于 极客时间 郑雨迪老师的《深入拆解 Java 虚拟机》课程,通过课后反思以及借鉴各位学友的发言总结,现整理出自己的知识架构,以便日后温故知新,查漏补缺。

关注本人公众号,第一时间获取最新文章发布,每日更新一篇技术文章。

04 JVM是如何执行方法调用的(上)

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Wesley13 Wesley13
2年前
java重载和重写的区别
一、重载重载方法的规则:1、重载是针对在同一个类中。2、重载方法名一个样。3、参数列表:被重载的方法必须改变参数列表。4、返回类型: 可以改变返回类型。5、修饰符:可以改变修饰符。6、异常:可以声明新的或者更广泛的异常。其中:1.方法重载是让类以统一的方式处理不同类型数据的一种手段。多个同名函数同时
Easter79 Easter79
2年前
Typescript 常见的几种函数重载方法详解与应用示例
所谓的重载,其实就是使用相同的函数名,传入不同数量的参数或不同类型的参数,以此创建出多个方法或产生不同结果。1\.最常见的,也就是根据定义傻瓜式地判断参数类型与数量functionshowPerson(name,...others){console.log(name,others)}
Stella981 Stella981
2年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Easter79 Easter79
2年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
2年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Stella981 Stella981
2年前
JVM总结
重载与重写在Java程序里,如果同一个类中出现多个名字相同,并且参数类型相同的方法,那么它无法通过编译。也就是说,在正常情况下,如果我们想要在同一个类中定义名字相同的方法,那么它们的参数类型必须不同。这些方法之间的关系,我们称之为重载。重载的方法在编译过程中即可完成识别。具体到每一个方法调用,Java编译器会根据所传入参数的声明类型
Wesley13 Wesley13
2年前
Java中方法的重载与覆盖(随笔01)
方法重载(Overlord)。方法重载:指在同一个类中,允许在一个以上的同名方法,只要它们的参数列表不同即可,与修饰符和返回值类型无关(例如:构造方法重载)。。参数列表:个数不同,数据类型不同,顺序不同;。重载方法调用:JVM通过方法的参数列表,调用不同的方法。!(https://oscimg.oschina.net/oscnet/0
小万哥 小万哥
2个月前
深入理解 Java 方法重载与递归应用
Java方法重载方法重载允许在同一个类中定义多个具有相同名称的方法,但参数列表必须不同。语法:javareturnTypemethodName(parameter1,parameter2,...,parameterN)//方法体示例:javapublicc