深入拆解 Java 虚拟机
郑雨迪
Oracle 高级研究员,计算机博士
87446 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 40 讲
模块四:黑科技 (3讲)
深入拆解 Java 虚拟机
15
15
1.0x
00:00/00:00
登录|注册

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

接口方法的调用
静态方法的调用
常量池中的接口符号引用和非接口符号引用
实际引用的确定
解析符号引用
invokestatic、invokespecial、invokevirtual、invokeinterface
类名、方法名、方法描述符
形式参数类型的继承关系
三个阶段的选取重载方法
参数类型不同
生成桥接方法的例子
符号引用的解析
Java虚拟机中的静态绑定与动态绑定
Java中的重载与重写
解析算法
符号引用的存储
静态绑定与动态绑定
调用指令
Java虚拟机识别方法的关键
重载方法的识别
重载方法的编译过程
同类中的方法重载
总结与实践
调用指令的符号引用
JVM的静态绑定和动态绑定
重载与重写
JVM方法调用执行

该思维导图由 AI 生成,仅供参考

前不久在写代码的时候,我不小心踩到一个可变长参数的坑。你或许已经猜到了,它正是可变长参数方法的重载造成的。(注:官方文档建议避免重载可变长参数方法,见[1]的最后一段。)
我把踩坑的过程放在了文稿里,你可以点击查看。
void invoke(Object obj, Object... args) { ... }
void invoke(String s, Object obj, Object... args) { ... }
invoke(null, 1); // 调用第二个invoke方法
invoke(null, 1, 2); // 调用第二个invoke方法
invoke(null, new Object[]{1}); // 只有手动绕开可变长参数的语法糖,
// 才能调用第一个invoke方法
当时情况是这样子的,某个 API 定义了两个同名的重载方法。其中,第一个接收一个 Object,以及声明为 Object…的变长参数;而第二个则接收一个 String、一个 Object,以及声明为 Object…的变长参数。
这里我想调用第一个方法,传入的参数为 (null, 1)。也就是说,声明为 Object 的形式参数所对应的实际参数为 null,而变长参数则对应 1。
通常来说,之所以不提倡可变长参数方法的重载,是因为 Java 编译器可能无法决定应该调用哪个目标方法。
在这种情况下,编译器会报错,并且提示这个方法调用有二义性。然而,Java 编译器直接将我的方法调用识别为调用第二个方法,这究竟是为什么呢?
带着这个问题,我们来看一看 Java 虚拟机是怎么识别目标方法的。

重载与重写

在 Java 程序里,如果同一个类中出现多个名字相同,并且参数类型相同的方法,那么它无法通过编译。也就是说,在正常情况下,如果我们想要在同一个类中定义名字相同的方法,那么它们的参数类型必须不同。这些方法之间的关系,我们称之为重载。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文深入探讨了JVM方法调用的执行过程,以及Java编译器在选择重载方法时的逻辑。作者详细介绍了方法的重载和重写,以及Java虚拟机中的静态绑定和动态绑定。文章还提到了重载方法在编译过程中的识别和选择规则,以及子类中重载和重写方法的关系。此外,作者指出方法重写是多态的一种体现方式,允许子类在继承父类功能的同时拥有自己独特的行为。通过实例分析,读者可以快速了解JVM方法调用的执行过程,以及Java编译器在选择重载方法时的逻辑。文章内容深入浅出,适合对JVM方法调用过程感兴趣的读者阅读。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《深入拆解 Java 虚拟机》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(111)

  • 最新
  • 精选
  • Thomas
    置顶
    看明白了......这篇真好
    2018-07-27
    9
    41
  • jiaobuchongจุ๊บ
    参考老师最后的例子,写了博客总结了一下:https://blog.csdn.net/jiaobuchong/article/details/83722193,欢迎拍砖。

    作者回复: 赞!

    2018-11-06
    2
    47
  • 曲东方
    Merchant类中actionPrice方法返回值类型为Number NaiveMerchant类中actionPrice方法返回值类型为Double NaiveMerchant类生成的字节码中有两个参数类型相同返回值类型不同的actionPrice方法 Method actionPrice:(DLCustomer;)Ljava/lang/Double; Method actionPrice:(DLCustomer;)Ljava/lang/Number; // 桥接到返回值为double的方法 flags: ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC 方法返回值不同为何也要产生桥接方法呢? 为了保证重写语义? 不知为何javac在编译 NaiveMerchant naiveMerchant = new NaiveMerchant(); Number number = naiveMerchant.actionPrice(1d, null) // 特意要求Number类型的返回值(方法描述符) 时,总invokevirtual到Method NaiveMerchant.actionPrice:(DLCustomer;)Ljava/lang/Double,这又是为什么呢? 附jdk版本 java version "1.8.0_172" Java(TM) SE Runtime Environment (build 1.8.0_172-b11) GraalVM 1.0.0-rc5 (build 25.71-b01-internal-jvmci-0.46, mixed mode)

    作者回复: 1 对的,为了保证重写语义。 2 生成的桥接方法还有一个acc_synthetic标记,代表对程序不可见。因此javac不能直接选取那个方法。

    2018-08-11
    7
  • vimfun
    老师,public final 或 public static final 的方法,是不是在 虚拟机中解析为静态绑定的

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

    2018-07-27
    6
  • 杨春鹏
    老师,关于方法调用的字节码指令中的invokespecial:调用实现接口的默认方法。 我测试了一下,发现子类中调用实现接口的默认方法还是使用的invokeinrerface。

    作者回复: 多谢指出!这里我指的是使用super关键字调用所实现接口的默认方法。

    2018-07-27
    3
    4
  • 小兵
    invokespecial:用于调用私有实例方法、构造器,以...和所实现接口的默认方法。 这里所实现接口的默认方法具体是指什么?

    作者回复: 接口的default方法,可能这样写比较清楚些

    2018-12-06
    2
    2
  • 王侦
    老师,最后那个例子能不能重新整理一下?说明一下操作步骤。不知道怎么操作!是写在一个文件还是多个文件?而且编译时报两个错误:一个是VIP要有一个类,一个是NaiveMerchant报错?

    作者回复: 多个文件。我这边代码实际上是分开的,上传时合成一个代码框了。回头我改一下。

    2018-10-26
    2
  • 陈树义
    文章开头的例子,我在JDK8环境下写了个例子测试,发现貌似和文中所说的不一致。 不知道是不是因为JDK版本问题,还是我例子有问题?

    作者回复: 我在java8和java10里测得的都一样

    2018-07-27
    2
  • 易水寒
    给下面某人解释一个问题,final[3][4]指的是参考下面的链接3,4链接,论文当中引用了别人的东西都这么写

    作者回复: 谢谢!我之后会统一一下引用方式,方便在文中就能点击。

    2018-09-26
    1
  • Go Ashton
    如果没有找到,在 C 所直接实现或间接实现的接口中搜索” 能否有个例子,什么是直接实现?什么是间接实现? 可能我知道这是什么,但叫法不同

    作者回复: C implements Interface1,Interface1 extends Interface2,C直接实现Interface1,间接实现Interface2。 如果你知道更加通用的叫法,麻烦留言告诉我哈

    2018-09-18
    2
    1
收起评论
显示
设置
留言
99+
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部