java字节码执行原理_《Java 底层原理》Java 字节码详解

前言

我们在开发中会遇到一些Java的执行超出我们的想象,但是又不知道他为什么会这样执行,这个时候我们就需要能够知道他编译后Class文件是什么样子的,并且理解字节码的含义。

Java字节码的原理

进制

class文件就是字节码文件,直接是打不开,打开也是乱码,需要解析才能看明白里面的内容。

现在存在很多语言都是允许在Jvm上,比如Kotlin。 他们其实就是通过编译也编译成Jvm认识的.class 文件即可。

大端和小端

大端模式:是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:

地址由小向大增加,而数据从高位往低位放;这和我们的阅读习惯一致。

小端模式:是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,这种存储模式将地址的高低和数据位权有效地结合起来,

高地址部分权值高,低地址部分权值低。

字节码文件内容组成结构

Java class文件的内容结构

693d68883c0365d8ede3504e6ce5eb8b.png

下面解析一下一个不太好理解的结构。

1. 魔数:用于判断这个文件是不是class合格的文件。

2. 次版本号和主板本号:主板本号加次版本号用于判断这个class文件是否能被这个版本的Jvm 解析, 比如jdk8的class就不能被java7版本的Jvm解析。

3. 常量池个数,最小是1,真实的常量池个数是2个字节计算出来的数量 - 1。

下面是常量池的字节码结构(u1 就是一个字节,u2 就是两个字节,类推):

5f7fd0bd97b55d3469d9e3985f4fa5dd.png

4. 类的访问控制权限

aaa533b585e5cde25d811df127fbd354.png

补充 :Acc_static                               0x0008         static 修饰

7fff17b1a82bb1df5c8f91b503c6644a.png

举个案例:

String[] 数组通过字节码表示是[Ljava/lang/String;

5. 类的成员变量字节码格式:

filed_info: {

u2 access_flags; -- 属性的访问类型和修饰符

u2 name_index; -- 成员变量的名字,指向常量池的地址

u2 descriptor_index;

u2 attributes_count;

attribute_info attributes[attributes_count];

}

6. 方法的字节码格式:

method_info {

u2 access_flags; -- 方法的访问属性和修饰符

u2 name_index; -- 方法的名字,指向常量池的地址

u2 descriptor_index; -- 描述符字符串,指向常量池地址,mian方法的描述符([java/lang/String;)v

u2 attributes_count; -- 对应下面的code_attribute

attribute_info attributes[attributes_count];

}

一般一个类除了你定义的方法外还会存在两个方法,clinit 和 init 处理你的静态代码和默认构造函数。

方法字节码:还包含:

code_attribute { --Code_attribute包含某个方法、实例初始化方法、类或接口初始化方法的Java虚拟机指令及相关辅助信息

u2 attribute_name_index;--指向常量池,名称

u4 attribute_length;--后面全部的总长度

u2 max_stack;--用来给出当前方法的操作数栈在方法执行的任何时间点的最大深度

u2 max_locals;--用来给出分配在当前方法引用的局部变量表中的局部变量个数

u4 code_length;--给出当前方法code[]数组的字节数

u1 code[code_length];--给出了实现当前方法的Java虚拟机代码的实际字节内容(这些数字代码实际对应一些Java虚拟机的指令)

u2 exception_table_lentgh;  --异常的信息个数

{

u2 start_pc;--这两项的值表明了异常处理器在code[]中的有效范围,即异常处理器x应满足:start_pc≤x≤end_pc

u2 end_pc;--start_pc必须在code[]中取值,end_pc要么在code[]中取值,要么等于code_length的值

u2 handler_pc;--表示一个异常处理器的起点

u2 catch_type;--表示当前异常处理器需要捕捉的异常类型。为0,则都调用该异常处理器,可用来实现finally。

} exception_table[exception_table_lentgh];u2 attribute_count;--表示该方法的其它附加属性,

attribute_info attributes[attributes_count];--LineNumberTable、LocalVariableTable

}

Java方法所在行信息:

LineNumberTable_attribute{--被调试器用来确定源文件中由给定的行号所表示的内容,对应于Java虚拟机code[] 数组的哪部分

u2 attribute_name_index;

u4 attribute_length;

u2 line_number_table_length;

{

u2 start_pc;

u2 line_number;-- 该值必须与源文件中对应的行号相匹配

} line_number_table[line_number_table_length];

}

局部变量表信息:

LocalVariableTable_attribute{

u2 attribute_name_index;

u4 attribute_length;

u2 local_variable_table_length;

{

u2 start_pc;

u2 length;

u2 name_index;

u2 descriptor_index;--用来表示源程序中局部变量类型的字段描述符

u2 index;

} local_variable_table[local_variable_table_length];

}

7.类属性字节码格式:

attribute_info: {

u2 attribute_name_index;

u1 attribute_length;

u1 info[attribute_length];

}

字节码文件解析

我们一起看一下Java编译后的class文件:

8838bc7d541f9afd7cac0936794d2d6f.png

这个是按照16进制显示的,没有按照任何编码的方式进行解析过的原信息。

我们按照上面字节码文件内容组成结构,来解析一下这个字节码文件

魔数:cafe babe 就表示这个是class 文件,Jvm才识别。

次版本号:0000

主版本号:0034

常量池数量:0021 就是2*16 + 1 33个常量池,但是需要减一,得到32个常量池。

常量池信息:前一个字节是tag 表示常量池的类型: oa 等于10 从常量池结构图可以找到时 constent_Methodref_info 这个类型,后面读取4个字节 00 0600 12;

00 06 表示constent_class_info的索引项;00 12 表示constent_nameAndType_info 名称和类型描述符的索引项,一次解析32个常量池。

特殊说明: 01类型的常量池,需要根据length 的长度动态解析。 比如 tag : 01  length : 0006   字符串:3c69 6e69 743e。

类的控制访问权限:0021 表示:0020加0001组合,说明是...和public 。

类名:0005 间接引用常量池第5个常量池

父类名:0006 间接引用常量池第6个常量池

接口数量:0001 实现一个接口。

接口数组:0007 指向常量池 第7个常量池,如果接口数量为零则不出现。

成员变量数量:0000 表示没有成员变量。

成员变量数组:如果成员变量数量为零则不占用字节。

方法数量:0002  两个方法,

方法数组:0001:修饰词pubilc;0008:方法名,指向常量池;0009 :描述符,指向常量池 ;0001:code_attributes的数量;

开始解析code_attribute 000a:code_attribute名称,指向常量池;0000 002f :attribute的长度47;0001:max_stack 操作数栈;0001:max_locals 局部变量个数;0000 0005 :code的长度; 2ab7 0001 b1 :code的内容就是操作虚拟机的指令信息; 00 00 :异常信息没有;00 02:表是其他附加信息有两个。

开始解析LineNumberTable_attribute :00 0b:指向常量池,就是指的lineNumberTable;00 0000 06:指的是这个信息的长度;00 01 :line_number_table_length;

00 00:start_pc ;  00 03 :Java这个方法的代码行号。

开始解析LocalVariableTable_attribute  00 0c:额外信息的名字,指向常量池;00 0000 0c:该信息长度;00 01:variable_table 信息的长度;00 00:start_pc;

00 05:长度;000d:指向常量池,局部变量描述符this;00 0e:指向常量池,类信息描述符;

解析方法字节码的过程中init 方法解析完成后,中间出现0000 无法解析,我猜是clinit 方法的解析,但是因为我们写所以使用0000 表示了。

类属性数量:

类属性数组:0001:第一次属性;  0010:指向常量池;  0000:不知道; 0002:第二个属性; 0011:指向常量池。

到此字节码文件全部解析完毕, 中间有一点瑕疵,后续学习中改进。

总结

字节码学习,让我们了解Java底层的实现有巨大的帮助。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/338849.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言学习笔记--位运算

这一节主要说的是位运算,计算机中的执行速度:位运算 > 加减 > 乘除 > 求余位运算就是将数字转换成二进制后进行运算,之后再将数字转换成原来的进制与运算:当两个数相与时,只有都为l的时候结果才为1&#xff0…

openshift学习_在OpenShift上将JMS与JBoss A-MQ结合使用。 学习了有关远程客户端和加密的经验。...

openshift学习OpenShift是“红帽开发的开放式混合云应用程序平台”。 它具有不同的风格,对于大多数您想做的事情,最有趣的部分是公共云应用程序开发和托管平台“ OpenShift Online ”。 您可以轻松地尝试一下,因为在云中使用OpenShift Online…

mathtype运行时错误48_在office中无法使用MathType该怎么办?

想必大家都遇到过在office中无法使用MathType的情况,那么遇到这种情况的话大家应该怎么来解决呢?首先这样的现象一般为:word或者ppt中没有mathtype选项,或者选项打开提示文件未找到:MathPage.WLL。错误提示或者甚至运行…

谈谈C语言中的杂项运算符

在C语言中,还有一些重要的运算符,例如:sizeof()、&、* 、 ?: 。我们把上述的这些运算符归为杂项运算符,下面我将详细介绍这些杂项运算符。下面的表格列出了 C 语言支持的所有杂项运算符:运算符解释例子sizeof()返…

java集合的添加方法_深入理解java集合框架之---------Arraylist集合 -----添加方法

Arraylist集合 -----添加方法1、add(E e) 向集合中添加元素/*** 检查数组容量是否够用* param minCapacity*/public void ensureCapacity(int minCapacity){modCount;int oldCapacity elementData.length;if(minCapacity > oldCapacity){Object oldData[] elementData;int…

jenkins java_具有WildFly,Arquillian,Jenkins和OpenShift的Java EE 7部署管道

jenkins java技术提示#54展示了如何Arquillianate(Arquillianize?)一个现有的Java EE项目并在WildFly在已知主机和端口上运行的远程模式下运行这些测试。 技术提示#55展示了当WildFly在OpenShift中运行时如何运行这些测…

matplotlib 折线图_漂亮图表也可信手拈来,一文学会用Python绘制堆积折线图

今天咱们还是接着上次的话题,继续和大家聊聊关于Python绘图相关的东东哦,上次已经和大家讨论完了如何给自己所绘制的图表中添加装饰线以及修改装饰线密度的方法,今天呢,咱们再聊点的新的东东哦,还是和大家继续深耕Pyth…

C语言 | 赋值与运算符

本章以鸡兔同笼为例,讲解赋值语句和一些简单的运算符。相关知识点:scanf(" %d " , &i ); 输入函数,表示输入一个整数(%d),赋值给 i(&i)C语言中加法运算符为 减法…

菜鸟学java要多久_菜鸟学java,根本停不下来!

位运算符&: 两个2进制的操作数,同一位数的两个数如果有一个为0结果就为0,两个都为1才是1.| : 两个2进制的操作数,同一位数的两个数如果有一个为1,两个都为0才是0.^ : 两个2进制的操作数,同一位数的两个数如果相同为0,不同为1.位移运算符<< 左移:把第一个二进制的操作…

响应式多级菜单 侧边菜单栏_使用纯HTML和OmniFaces构建动态响应的多级菜单

响应式多级菜单 侧边菜单栏最近&#xff0c;我不得不使用JSF 2.2创建一个响应式多级菜单。 要求&#xff1a;菜单应&#xff1a; 从后端使用动态结构创建 React灵敏&#xff0c;例如对桌面和移动设备友好 有带有导航链接的子菜单项 支持触摸事件 支持键盘辅助功能 PrimeF…

python列表中随机两个_随机化两个列表并在python中维护顺序

随机化两个列表并在python中维护顺序说我有两个简单的清单&#xff0c;a [Spears, "Adele", "NDubz", "Nicole", "Cristina"]b [1,2,3,4,5]len(a) len(b)我想做的是将a和a随机化&#xff0c;但要保持顺序。 因此&#xff0c;类似&a…

C语言中的头文件

头文件是扩展名为 .h 的文件&#xff0c;包含了 C 函数声明和宏定义&#xff0c;被多个源文件中引用共享。有两种类型的头文件&#xff1a;程序员编写的头文件和编译器自带的头文件。在程序中要使用头文件&#xff0c;需要使用 C 预处理指令 #include 来引用它。前面我们已经看…

ceph-rest-api_快速检查REST API是否有效的方法-从清单文件中获取详细信息

ceph-rest-api在某些情况下&#xff0c;您可能想快速验证部署在开发&#xff0c;测试或生产环境中的REST API是否完全可以访问。 一种常见的实现方法是构建通用资源&#xff0c;该资源可提供例如已部署API的版本。 您可以手动触发对此资源的请求&#xff0c;或者更好的是&#…

set trans 必须是事务处理的第一个语句_MySQL中特别实用的几种SQL语句送给大家

在写SQL时&#xff0c;经常灵活运用一些SQL语句编写的技巧&#xff0c;可以大大简化程序逻辑。减少程序与数据库的交互次数&#xff0c;有利于数据库高可用性&#xff0c;同时也能显得你的SQL很牛B&#xff0c;让同事们眼前一亮。实用的SQL1.插入或替换如果我们想插入一条新记录…

C语言预处理命令总结

预处理指令是以#号开头的代码行&#xff0c;# 号必须是该行除了任何空白字符外的第一个字符。# 后是指令关键字&#xff0c;在关键字和 # 号之间允许存在任意个数的空白字符&#xff0c;整行语句构成了一条预处理指令&#xff0c;该指令将在编译器进行编译之前对源代码做某些转…

突破极限–如何使用AeroGear Unified Push for Java EE和Node.js

在2014年底的AeroGear队宣布红帽的JBoss统一推送服务器的可用性xPaaS 。 让我们仔细看看&#xff01; 总览 统一推送服务器允许开发人员将本地推送消息发送到Apple的推送通知服务&#xff08;APNS&#xff09;和Google的云消息传递&#xff08;GCM&#xff09;。 它具有内置的…

java 运行os文件路径_Java获取文件路径的几种方式

关于绝对路径和相对路径&#xff1a; 绝对路径就是你的主页上的文件或目录在硬盘上真正的路径&#xff0c;(URL和物理路径)例如&#xff1a;C:xyz est.txt 代表了test.txt文件的绝对路径。http://www.sun.com/index.htm也代表了一个URL绝对路径。相 对路径&#xff1a;相对与某…

mysql 分词搜索_实战 | canal 实现Mysql到Elasticsearch实时增量同步

题记关系型数据库Mysql/Oracle增量同步Elasticsearch是持续关注的问题&#xff0c;也是社区、QQ群等讨论最多的问题之一。 问题包含但不限于&#xff1a; 1、Mysql如何同步到Elasticsearch? 2、Logstash、kafka_connector、canal选型有什么不同&#xff0c;如何取舍&#xff1…

C memset 踩坑

一、前言memset 作为对内存初始化的函数&#xff0c;还是有不少坑和误区的&#xff0c;今天就来对这个函数作一个总结。二、函数作用最简单的调用就是将一个数组清零&#xff0c;代码如下&#xff1a;const int maxn 1024; int a[maxn]; memset(a, 0, sizeof(a)); // a[0]a[1…

eap和psk_针对WildFly和EAP运行Java Mission Control和Flight Recorder

eap和pskJava Mission Control &#xff08;JMC&#xff09;使您可以监视和管理Java应用程序&#xff0c;而无需引入通常与这些类型的工具相关的性能开销。 它使用为正常的JVM动态优化而收集的数据&#xff0c;从而形成了一种非常轻量级的方法来观察和分析应用程序代码中的问题…