重载和重写

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

重载的方法在编译过程中就可完成识别。具体到每一个方法的调用,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是如何执行方法调用的(上)的更多相关文章

  1. 04 JVM是如何执行方法调用的(下)

    虚方法调用 Java 里所有非私有实例方法调用都会被编译成 invokevirtual 指令,而接口方法调用会被编译成 invokeinterface 指令.这两种指令,均属于 Java 虚拟机中的虚 ...

  2. JVM(十二):方法调用

    JVM(十二):方法调用 在 JVM(七):JVM内存结构 中,我们说到了方法执行在何种内存结构上执行:Java 方法活动在虚拟机栈中的栈帧上,栈帧的具体结构在内存结构中已经详细讲解过了,下面就让我们 ...

  3. 多态:JVM是如何进行方法调用的

    在我们平时的工作学习中写java代码时,如果我们在同一个类中定义了两个方法名和参数类型都相同的方法时,编译器会直接报错给我们.还有在代码运行的时候,如果子类定义了一个与父类完全相同的方法的时候,父类的 ...

  4. 深入解析多态和方法调用在JVM中的实现

    深入解析多态和方法调用在JVM中的实现 1. 什么是多态 多态(polymorphism)是面向对象编程的三大特性之一,它建立在继承的基础之上.在<Java核心技术卷>中这样定义: 一个对 ...

  5. 第31篇-方法调用指令之invokevirtual

    invokevirtual字节码指令的模板定义如下: def(Bytecodes::_invokevirtual , ubcp|disp|clvm|____, vtos, vtos, invokevi ...

  6. 图解JVM执行引擎之方法调用

    一.方法调用 方法调用不同于方法执行,方法调用阶段的唯一任务就是确定被调用方法的版本(即调用哪一个方法),暂时还不涉及方法内部的具体运行过程.Class文件的编译过程中不包括传统编译器中的连接步骤,一 ...

  7. jvm 字节码执行 (一)方法调用

    “虚拟机”是一个相对于“物理机”的概念,这两种机器都有代码执行能力,其区别是物理机的执行引擎是直接建立在处理器.硬件.指令集和操作系统层面上,而虚拟机的执行引擎是 由自己实现的,因此可以自行制定指令集 ...

  8. JVM方法调用过程

    JVM方法调用过程 重载和重写 同一个类中,如果出现多个名称相同,并且参数类型相同的方法,将无法通过编译.因此,想要在同一个类中定义名字相同的方法,那么它们的参数类型必须不同.这种方法上的联系就是重载 ...

  9. Spring杂谈 | 从桥接方法到JVM方法调用

    前言 之所以写这么一篇文章是因为在Spring中,经常会出现下面这种代码 // 判断是否是桥接方法,如果是的话就返回这个方法 BridgeMethodResolver.findBridgedMetho ...

随机推荐

  1. SqlServer作业指定目标服务器

    用SSMS生成数据库作业的创建脚本的时候,有一步是sp_add_jobserver操作: EXEC @ReturnCode = msdb.dbo.sp_add_jobserver @job_id = ...

  2. LeetCode Excel Sheet Column Number 表列数

    题意:天啊!我竟然看不懂题意,还去翻别人的代码才懂!给定一个字符串,求该字符串二十六进制的总值. 思路:'A'~'Z'就是1到26,"AA"=26+1=27,"BA&qu ...

  3. IFEO 映像文件劫持

    “映像劫持”,也被称为“IFEO”(Image File Execution Options) 映像劫持的根本就是被恶意篡改了注册表HKEY_LOCAL_MACHINE\SOFTWARE\Micros ...

  4. IOS 绘制条纹背景

    @interface NJViewController () @property (weak, nonatomic) IBOutlet UITextView *contentView; - (IBAc ...

  5. POJ 3041 Asteroids (对偶性,二分图匹配)

    题目:POJ 3041 Asteroids http://poj.org/problem?id=3041 分析: 把位置下标看出一条边,这显然是一个二分图最小顶点覆盖的问题,Hungary就好. 挑战 ...

  6. RAC基本使用

    @interface ViewController () @property (weak, nonatomic) IBOutlet lwRedView *redView; @property (wea ...

  7. 使用canvas给图片添加水印

    css部分 .clip { position: absolute; clip: rect(0 0 0 0); } html部分 <input type="file" id=& ...

  8. 复习C++_基础、函数、数组、字符串

    程序的开发过程 程序 源程序:用源语言写的,有待翻译的程序: 目标程序:源程序通过翻译程序加工以后生成的机器语言程序: 可执行程序:连接目标程序以及库中的某些文件,生成的一个可执行文件,例如Windo ...

  9. pandas 代码

    def get_train_data(): df = pd.read_csv('data/train.csv', encoding='utf_8') # df1 = pd.read_csv('data ...

  10. Linux环境下使用xampp配置php开发环境

    XAMPP (Apache+MySQL+PHP+PERL)是一个功能强大的建站集成软件包.这个软件包原来的名字是LAMPP,但是为 了避免误 解,最新的几个版本就改名为 XAMPP 了.它可以在Win ...