重载和重写

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

重载的方法在编译过程中就可完成识别。具体到每一个方法的调用,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. docker使用centos7系统构建oraclejdk镜像

    FROM centos:7.4.1708 MAINTAINER huqiang:2018/10/12 ENV JAVA_VERSION=8 \ JAVA_UPDATE=191 \ JAVA_BUILD ...

  2. 使用Java+SAP云平台+SAP Cloud Connector调用ABAP On-Premise系统里的函数

    最近Jerry接到一个原型开发的任务,需要在微信里调用ABAP On Premise系统(SAP CRM On-Premise)里的某些函数.具体场景和我之前的公众号文章 Cloud for Cust ...

  3. An incomplete guide to LaTex

    LATEX入门与提高.陈志杰数理学院喜闻乐见的电子书.这本电子书由于是图片版本,所以无法使用搜索功能,幸亏目录详细. LaTeX Beginner's Guide.latex使用者都是从模版开始学习, ...

  4. 我的Linux学习之路的感悟

    首先要跟大家说声抱歉,这么久一直没有更新,有负大家对我的期望. 半年的Linux运维的学习到目前已工作一个月零9天,这一路走来的艰辛和挣扎只有自己最清楚. 首先要感谢公司的同事的宽容接纳和耐心指点.感 ...

  5. tmux 用z关闭之后的恢复

    ctrl+b 然后z是全屏 但是如果是ctrl+z就是关闭窗口了 tmux ls看所有窗口 然后 tmux attach -t 2或者3就恢复

  6. Hystrix + Hystrix Dashboard搭建(Spring Cloud 2.X)

    本机IP为  192.168.1.102 一.搭建Hystrix Dashboard 1.   新建 Maven 项目  hystrix-dashboard 2. pom.xml <projec ...

  7. 如果int x=20, y=5,则语句System.out.println(x+y +""+(x+y)+y); 的输出结果是()

    答案是25255 小括号优先级高,所以先算小括号内的x+y=25 然后再算前面的x+y=25 但是中间有个空的字符串,java会把这个空字符串后面的都当成字符串看待,所以结果是25255

  8. 10个HTML5 实战教程 提升你的综合开发能力

    HTML5 作为下一代网站开发技术,无论你是一个 Web 开发人员或者想探索新的平台的游戏开发者,都值得去研究.借助尖端功能,技术和 API,HTML5 允许你创建响应性.创新性.互动性以及令人惊叹的 ...

  9. java调用摄像头

    http://blog.csdn.net/xing_sky/article/details/43482213 原文地址:http://blog.csdn.net/zajin/article/detai ...

  10. 黑马基础阶段测试题:创建Phone(手机)类,Phone类中包含以下内容:

    package com.swift; public class Phone { private String pinpai; private int dianliang; public String ...