【JVM笔记】方法的调用—虚方法与非虚方法

目录

虚方法与非虚方法的定义

虚拟机中提供的调用指令

普通调用指令

动态调用指令

关于invokedynamic指令

方法重写的本质

虚方法表


虚方法与非虚方法的定义

如果方法在编译期就确定了具体的调用版本,这个版本在运行时是不可改变的。这样的方法称为非虚方法

静态方法、私有方法、final 方法、实例构造器、父类方法都是非虚方法,其它方法则称为虚方法

虚拟机中提供的调用指令

普通调用指令

1. invokestatic 调用静态方法,解析阶段确定唯一方法版本(非虚方法)

2. invokespecial 调用 <init> 方法、私有及父类方法,解析阶段确定唯一方法版本(非虚方法)

3. invokevirtual 调用所有虚方法

4 invokeinterface 调用接口方法

动态调用指令

5. invokedynamic 动态解析出需要调用的方法,然后执行

前四条指令固化在虚拟机内部,方法的调用执行不可人为干预,而 invokedynamic 指令则支持由用户确定方法版本。其中 invokestatic 指令和 invokespecial 指令调用的方法称为非虚方法,其余的(final修饰的除外)称为虚方法

关于invokedynamic指令

JVM 字节码指令集一直比较稳定,一直到 Java7 中才增加了一个 invokedynamic 指令,这是 Java 为了实现 [动态类型语言] 支持而做的一种改进

但是在 Java7 中并没有提供直接生成 invokedynamic 指令的方法,需要借助 ASM 这种底层字节码工具来产生 invokedynamic 指令。直到 Java8 的 Lambda 表达式出现,invokedynamic 指令的生成,在 Java 中才有了直接的生成方式

Java7 中增加的动态语言类型支持的本质是对 Java 虚拟机规范的修改,而不是对 Java 语言规则的修改,这一块相对来讲比较复杂,增加了虚拟机中的方法调用,最直接的受益者就是运行在 Java 平台的动态语言的编译器

方法重写的本质

1. 找到操作数栈顶的第一个元素所执行的对象的实际类型,记作 C

2. 如果在类型 C 中找到与常量中的描述符合简单名称都相符的方法,则进行访问权限校验,如果通过则返回这个方法的直接引用,查找过程结束。如果不通过,则返回 Java.lang.IllegalAccessError(IllegalAccessError:程序试图访问或修改一个属性或调用一个方法,这个属性或方法,你没有访问权限。一般的,这个会引起编译器异常。这个错误如果发生在运行时,就说明一个类发生了不兼容的改变)

3. 否则,按照继承关系从下往上依次对 C 的各个父类进行第二步的搜索和验证过程

4. 如果始终没有找到合适的方法,则抛出 Java.lang.AbstractMethodError 异常

虚方法表

在面向对象的编程中,会很频繁的使用到动态分派,如果在每次动态分派的过程中都要重新在类的方法元数据中搜索合适的目标的话就可能影响到执行效率。因此,为了提高性能,JVM 采用在类的方法区建立一个虚方法表(virtual method table)(非虚方法不会出现在表中)。使用索引表来代替查找

每个类中都有一个虚方法表,表中存放各个方法的实际入口

虚方法表会在类加载的链接阶段被创建并开始初始化,类的变量初始值准备完成之后,JVM 会把该类的方法表也初始化完毕

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

java小白。。

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值