jvm004 解析与分派
解析
所有方法调用中的目标方法在Class文件里面都是常量池中的符号引用,在类加载的解析阶段,会将其中的一部分符号引用转化为直接引用。这种解析的前提是:方法在程序真正运行之前就有一个可确定的调用版本,并且这个方法的调用版本在运行期是不可改变的,即“编译期可知,运行期不可变”,这类目标的方法的调用称为解析(Resolution)。
分派
解析调用一定是个静态的过程,在编译期就完全确定,在类加载的解析阶段就将涉及的符号引用全部转变为可以确定的直接引用,不会延迟到运行期 再去完成。而分派(Dispatch)调用则可能是静态的也可能是动态的。于是分派方式就有静态分派和动态分派。
java是一门面向对象的编程语言,具备面向对象的三个基本特征:继承、封装、多态。
接下来我将演示下分派调用过程来揭示多态性的一些最基本的体现。如重载(Overload)和重写(Override)在jvm中是如何实现的。
1、静态分派
静态分派发生在编译阶段,不是由jvm执行的,典型的应用是重载(Overload)。
静态分派的最直接的解释是在重载的时候是通过参数的静态类型而不是实际类型作为判断依据的。因此在编译阶段,Javac编译器会根据参数的静态类型决定使用哪个重载版本。
方法静态分派代码演示:
/**
* 方法静态分派
*
* @author sun
*
*/
public class StaticDispatch {
static abstract class Human { } static class Man extends Human { } static class Woman extends Human { } public void sayHello(Human guy) {
System.out.println("hello,guy");
} public void sayHello(Man guy) {
System.out.println("hello,sun");
} public void sayHello(Woman guy) {
System.out.println("hello,ting");
} public static void main(String[] args) {
Human man = new Man();
Human woman = new Woman();
StaticDispatch staticDispatch = new StaticDispatch();
staticDispatch.sayHello(man);
staticDispatch.sayHello(woman);
}
}
运行结果:
hello,guy
hello,guy
对于有经验的程序员来说,出现上面的结果并不感到惊讶。接下来我们要分析为什么会出现这样的结果,但在分析之前,我们要明确两个概念。
即变量的静态类型和变量的实际类型。如下:
Human man = new Man();
Human 称为变量的静态类型;Man称为变量的实际类型。二者的区别在于静态类型在编译期是可知的,而实际类型是在运行期才确定,编译时并不知道一个对象的实际类型是什么。
// 实际类型变化
Human man = new Man();
man = new Woman();
// 静态类型变化
sr.sayHello((Man) man);
sr.sayHello((Woman) man);
在方法接收者已经确定是对象sr的前提下,使用哪个重载版本就完全取决于传入参数的数量和数据类型。代码中刻意使用了两个静态类型相同而实际类型不同的变量,编译器在重载时是通过参数的静态类型而不是实际类型作为判定依据的,man和woman的静态类型都是Human。静态类型在编译期可知,因此在编译阶段,编译期根据man和woman的静态类型为Human的事实,来选择public void sayHello(Human guy)作为调用方法,这就是方法重载的具体体现。
所有依赖静态类型来定位方法执行版本的分派动作称为静态分派。
2、动态分派
动态分派和多态性的体现-重写(Override)有着本质的联系。
/**
* 方法动态分派
*
* @author sun
*
*/
public class DynemicDispatch { static abstract class Human {
protected abstract void sayHello();
} static class Man extends Human { @Override
protected void sayHello() {
System.out.println("man say hello");
} } static class Woman extends Human { @Override
protected void sayHello() {
System.out.println("woman say hello");
} } public static void main(String[] args) {
Human man = new Man();
Human woman = new Woman();
man.sayHello();
woman.sayHello();
man = new Woman();
man.sayHello();
}
}
运行结果:
man say hello
woman say hello
woman say hello
显然这里不可能根据静态类型来决定调用那个方法。导致这个现象很明显的原因是因为这两个变量的实际类型不一样,jvm根据实际类型来分派方法执行版本。我们使用javap命令来查看这段代码的字节码。以下是该段代码main方法的字节码:
public static void main(java.lang.String[]);
Code:
0: new #16 // class Demo/DynemicDispatch$Man
3: dup
4: invokespecial #18 // Method Demo/DynemicDispatch$Man."<init>":()V
7: astore_1
8: new #19 // class Demo/DynemicDispatch$Woman
11: dup
12: invokespecial #21 // Method Demo/DynemicDispatch$Woman."<init>":()V
15: astore_2
16: aload_1
17: invokevirtual #22 // Method Demo/DynemicDispatch$Human.sayHello:()V
20: aload_2
21: invokevirtual #22 // Method Demo/DynemicDispatch$Human.sayHello:()V
24: new #19 // class Demo/DynemicDispatch$Woman
27: dup
28: invokespecial #21 // Method Demo/DynemicDispatch$Woman."<init>":()V
31: astore_1
32: aload_1
33: invokevirtual #22 // Method Demo/DynemicDispatch$Human.sayHello:()V
36: return
0~15行的字节码作用是建立man和woman的内存空间、调用Man和Woman类型的实例构造器的。
16、20两句把刚刚创建的两个对象的引用压到栈顶,这两个对象是将要执行的sayHello()方法的所有者,称为接收者(Receiver)!
17、21两句是方法调用指令,这两句指令最终的目标方法并不相同。
这需要说说jvm的invokevirtual指令了,这个指令的解析过程有助于我们更深刻理解重写的本质。该指令的具体解析过程如下:
找到操作数栈栈顶的第一个元素所指向的对象的实际类型,记为C
如果在类型C中找到与常量中描述符和简单名称都相符的方法,则进行访问权限的校验,如果通过则返回这个方法的直接引用,查找结束;如果不通过,则返回非法访问异常
如果在类型C中没有找到,则按照继承关系从下到上依次对C的各个父类进行第2步的搜索和验证过程
如果始终没有找到合适的方法,则抛出抽象方法错误的异常
从这个过程可以发现,在第一步的时候就在运行期确定接收者的实际类型,所以当调用invokevirtual指令就会把运行时常量池中符号引用解析为不同的直接引用,这就是方法重写的本质。我们把这种在运行期根据实际类型确定方法执行版本的分派称为动态分派。
jvm004 解析与分派的更多相关文章
- JAVA方法调用中的解析与分派
JAVA方法调用中的解析与分派 本文算是<深入理解JVM>的读书笔记,参考书中的相关代码示例,从字节码指令角度看看解析与分派的区别. 方法调用,其实就是要回答一个问题:JVM在执行一个方法 ...
- JVM 方法调用之静态分派
分派(Dispatch)可能是静态也可能是动态的,根据分派依据的宗量数可分为单分派和多分派.这两种分派方式的两两组合就构成了静态单分派,静态多分派,动态单分派,动态多分派这4种组合.本章讲静态分派. ...
- 深入理解Java虚拟机--中
深入理解Java虚拟机--中 第6章 类文件结构 6.2 无关性的基石 无关性的基石:有许多可以运行在各种不同平台上的虚拟机,这些虚拟机都可以载入和执行同一种平台无关的字节码(ByteCode),从而 ...
- 《深入理解Java虚拟机》-----第8章 虚拟机字节码执行引擎——Java高级开发必须懂的
概述 执行引擎是Java虚拟机最核心的组成部分之一.“虚拟机”是一个相对于“物理机”的概念 ,这两种机器都有代码执行能力,其区别是物理机的执行引擎是直接建立在处理器.硬件.指令集和操作系统层面上的,而 ...
- jvm 字节码执行 (一)方法调用
“虚拟机”是一个相对于“物理机”的概念,这两种机器都有代码执行能力,其区别是物理机的执行引擎是直接建立在处理器.硬件.指令集和操作系统层面上,而虚拟机的执行引擎是 由自己实现的,因此可以自行制定指令集 ...
- 深入理解Java虚拟机读书笔记5----虚拟机字节码执行引擎
五 虚拟机字节码执行引擎 1 运行时栈帧结构 ---栈帧是用于支持虚拟机进行方法调用和方法执行的数据结构,是虚拟机运行时数据区中的虚拟机栈的栈元素. ---栈帧中存储了方法的局部变 ...
- Java面试题 BAT 大公司面试题整理总结!
本文只列出了问题,答案还是需要需要自己的总结,很多时候自己总结出来的语言在面试时比硬背的效果好很多. 这些题目是网友去百度.小米.乐视.美团.58.猎豹.360.新浪.搜狐等一线互联网公司面试被问到的 ...
- BATJ等大厂最全经典面试题分享
金九银十,又到了面试求职高峰期,最近有很多网友都在求大厂面试题.正好我之前电脑里面有这方面的整理,于是就发上来分享给大家. 这些题目是网友去百度.蚂蚁金服.小米.乐视.美团.58.猎豹.360.新浪. ...
- tomcat架构分析(connector BIO 实现)
出处:http://gearever.iteye.com 在tomcat架构分析(概览)中已经介绍过,connector组件是service容器中的一部分.它主要是接收,解析http请求,然后调用本s ...
随机推荐
- 冒泡排序的python代码实现
li = [33, 2, 10, 1,564,880,8,99,51,3]# for i in range(len(li) - 1):# current = li[i]# next_v ...
- 教你怎么把iconfont转换成png透明图片
1.进入iconfont图标库,登陆.http://www.iconfont.cn/ 2.选择想要的图标加入购物车. 3.直接选中下载图标为png格式.
- int 与 int *
#include <iostream>using namespace std;int QKPass(int* , int , int); //若声明为 int QKPass(int, i ...
- sql还原(.sql文件还原)
第一步: 把还原文件直接拖到SQL Server 2012(或者其他版本)里面,这里以MyDB.sql为例
- 提升单元测试体验的利器--Mockito使用总结
为神马要使用Mockito? 在编写单元测试的时候,为了尽可能的保证隔离性,我们时常需要对某些不容易构造或者不容易获取或者对外部环境有依赖的对象,用一个虚拟的对象来创建以便于测试.假设你正在开发的的代 ...
- javaCV开发详解之7:让音频转换更加简单,实现通用音频编码格式转换、重采样等音频参数的转换功能(以pcm16le编码的wav转mp3为例)
javaCV系列文章: javacv开发详解之1:调用本机摄像头视频 javaCV开发详解之2:推流器实现,推本地摄像头视频到流媒体服务器以及摄像头录制视频功能实现(基于javaCV-FFMPEG.j ...
- socket套接字编程
一.概述 1.socket是一种进程间通信方式,既可以用于一台机器,也可以用于网络.常用语C/S模型. 2.可以跨越Windows和Linux操作系统,可以跨越不同语言. 3.注意网络字节序和主机字节 ...
- [编织消息框架][netty源码分析]4 eventLoop 实现类NioEventLoop职责与实现
NioEventLoop 是jdk nio多路处理实现同修复jdk nio的bug 1.NioEventLoop继承SingleThreadEventLoop 重用单线程处理 2.NioEventLo ...
- php访问数据库$result=$mysql_qurey('')判断是否是空值
在访问数据库后得到result值,前提是$relust为true,就是没有发生错误连接情况,但是查询的条件由于不满足导致返回值为空,此时判断就不能用!来决定是否有返回数据了,经过书籍搜索,用resul ...
- python 自定义回调函数
回调函数用起来比较爽.特别是在js中,满世界全是回调,那么在python中,怎么来优雅地实现自己的回调函数呢 下面贴一个我写的例子 class BaseHandler(object): def cra ...