04 JVM是如何执行方法调用的(上)
重载和重写
重载:同一个类中定义名字相同的方法,但是参数类型或者参数个数必须不同。
重载的方法在编译过程中就可完成识别。具体到每一个方法的调用,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是如何执行方法调用的(上)的更多相关文章
- 04 JVM是如何执行方法调用的(下)
虚方法调用 Java 里所有非私有实例方法调用都会被编译成 invokevirtual 指令,而接口方法调用会被编译成 invokeinterface 指令.这两种指令,均属于 Java 虚拟机中的虚 ...
- JVM(十二):方法调用
JVM(十二):方法调用 在 JVM(七):JVM内存结构 中,我们说到了方法执行在何种内存结构上执行:Java 方法活动在虚拟机栈中的栈帧上,栈帧的具体结构在内存结构中已经详细讲解过了,下面就让我们 ...
- 多态:JVM是如何进行方法调用的
在我们平时的工作学习中写java代码时,如果我们在同一个类中定义了两个方法名和参数类型都相同的方法时,编译器会直接报错给我们.还有在代码运行的时候,如果子类定义了一个与父类完全相同的方法的时候,父类的 ...
- 深入解析多态和方法调用在JVM中的实现
深入解析多态和方法调用在JVM中的实现 1. 什么是多态 多态(polymorphism)是面向对象编程的三大特性之一,它建立在继承的基础之上.在<Java核心技术卷>中这样定义: 一个对 ...
- 第31篇-方法调用指令之invokevirtual
invokevirtual字节码指令的模板定义如下: def(Bytecodes::_invokevirtual , ubcp|disp|clvm|____, vtos, vtos, invokevi ...
- 图解JVM执行引擎之方法调用
一.方法调用 方法调用不同于方法执行,方法调用阶段的唯一任务就是确定被调用方法的版本(即调用哪一个方法),暂时还不涉及方法内部的具体运行过程.Class文件的编译过程中不包括传统编译器中的连接步骤,一 ...
- jvm 字节码执行 (一)方法调用
“虚拟机”是一个相对于“物理机”的概念,这两种机器都有代码执行能力,其区别是物理机的执行引擎是直接建立在处理器.硬件.指令集和操作系统层面上,而虚拟机的执行引擎是 由自己实现的,因此可以自行制定指令集 ...
- JVM方法调用过程
JVM方法调用过程 重载和重写 同一个类中,如果出现多个名称相同,并且参数类型相同的方法,将无法通过编译.因此,想要在同一个类中定义名字相同的方法,那么它们的参数类型必须不同.这种方法上的联系就是重载 ...
- Spring杂谈 | 从桥接方法到JVM方法调用
前言 之所以写这么一篇文章是因为在Spring中,经常会出现下面这种代码 // 判断是否是桥接方法,如果是的话就返回这个方法 BridgeMethodResolver.findBridgedMetho ...
随机推荐
- 解决mysql连接输入密码提示Warning: Using a password on the command line interface can be insecure
有时候客户端连接mysql需要指定密码时(如用zabbix监控mysql)5.6后数据库会给出个警告信息 mysql -uroot -pxxxx Warning: Using a password o ...
- iOS界面设计切图小结
iOS界面设计切图小结 APR 12TH, 2013 1.基本尺寸 (1)界面 实际设计时按: iPhone4.4s:640px*960px iPhone5: 640px*1136px iPad:15 ...
- flash + php对称密钥加密的交互
这几天研究了下php和flash中的对称密钥加密的交互问题,经过研究以后决定,在项目中使用aes加密.问题也就来了,在flash中的加密数据如何与php的amf进行数据交互,最终决定使用base64编 ...
- python setup.py install 报错
python setup.py install 报错信息 [root@VM_25_28_centos psutil-2.0.0]# python setup.py install running in ...
- Vue源码学习二 ———— Vue原型对象包装
Vue原型对象的包装 在Vue官网直接通过 script 标签导入的 Vue包是 umd模块的形式.在使用前都通过 new Vue({}).记录一下 Vue构造函数的包装. 在 src/core/in ...
- vue 自定义动态弹框
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 牛客小白月赛5 I 区间 (interval) 【前缀和】
链接:https://www.nowcoder.com/acm/contest/135/I 题目描述 Apojacsleam喜欢数组. 他现在有一个n个元素的数组a,而他要对a[L]-a[R]进行M次 ...
- PAT 乙级 1003
题目 题目地址:PAT 乙级 1003 题解 规律观察题,本题的关键在于把题读懂,同时还有几个比较容易疏忽的地方需要注意:总之这道题要考虑的东西更多,细节上也要特别注意: 规律:“如果 aPbTc 是 ...
- python笔记-dict字典的方法2
#!/usr/bin/env python #-*- coding:utf-8 -*- ''' 概述: 使用键值(key-value)存储,具有极快的查找速度 注意:字典是无序的 key的特性: 1. ...
- 【PHP】常用的PHP正则表达式收集整理
匹配中文字符的正则表达式: [\u4e00-\u9fa5]评注:匹配中文还真是个头疼的事,有了这个表达式就好办了 匹配双字节字符(包括汉字在内):[^\x00-\xff]评注:可以用来计算字符串的长度 ...