关于Java字节码

关于Java字节码

1. 概述

从写Java文件到编译成字节码文件(也就是.class文件)的过程也就是Java文件编译的过程,我们所写的是Java文件而Java虚拟机编译的是字节码文件

2. class文件格式

class文件格式

3. 举个栗子来说明一下

①先写一个.java文件

Demo的java文件

②打开.class文件

Demo的class文件

3.1 magic 魔数

前四个字节为魔数,值为:0xCAFE BABE Java创始人 James Gosling制定 用来表示是class 文件 有人会问为什么为cafebaby,联想一下java的咖啡杯图标就知道了。

3.2 minor_version & major_version 版本号

minor_version & major_version对应 的16进制为 0000 0034 前两个字节为minor_version 为此版本号 后两个字节为主版本号。所有该文件的版本号为1.8。

版本号 JDK版本号
2e JDK1.2
2f JDK1.3
30 JDK1.4
31 JDK1.5
32 JDK1.6
33 JDK1.7
34 JDK1.8

3.3 常量池

在版本号之后的为常量池,常量池可以理解为Class文件中的资源仓库。他是Class文件结构中与其他项目关联最多的数据类型,也是占用Class文件空间最大的数据项之一,同时它还是在Class文件中第一个出现的表类型数据项目。由于常量池中的常量的数量是不固定的,所以在常量池的入口需要放置一项u2类型的数据,代表常量池容量计数值(constant_pool_count),这个计数是从1开始而不是从0开始的
常量池主要存放两大类字面量和符号引用,字面量如文本字符串,声明为final的常量值等,符号引用属于编译原理方面的概念包括三种常量:①类和接口的权限定名 ②字段的名称和描述符 ③方法名和描述符
常量池每一项常量都是一个表,jdk1.7之前有11种结构不同的表结构数据,在jdk1.7中又增加了三种下图为14种常量类型所代表的具体含义
常量所代表的具体含义

在魔数和版本号后面为常量池,0x0016 为常量池容量,十进制为22,这就代表了常量池中有21项常量,索引值范围为1~~21。在Class 文件格式规范制定的时候,设计者将第0项常量空出来是有特殊考虑的,这样做的目的在于满足后面某些指向常量池的索引值的数据在特定情况下需要表达“不引用任何常量池项目的含义”这种情况就可以吧索引置为0来表示。
0x07查表的标志列可以知道这个常量属于CONSTANT_Class_info类型 此类型代表一个类或者接口的符号引用。
CONSTANT_Class_info类型比较简单具体结构看下图:
CONSTANT_Class_info的结构
tag是标志位,它用于区分常量类型。name_index 是一个索引值 在这里值为0x0002 也即是指向了常量池里的第二个常量
0x01为常量池中的第二个常量根据标志列可知这个常量为CONSTANT_Utf8_info类型的常量,下图为常量结构

CONSTANT_Utf8_info常量的结构
length值说明了这个utf-8编码的字符串长度是多少字节,在这里为0x013表示19个字节,他后面紧跟着的长度为length字节的连续数据是一个使用utf-8缩略编码表示的字符串。
636f~~~6f 19个字节表示的是使用utf-8缩略编码表示的字符串。翻译完为:com/baidu/test/demo
我们现在已经分析了两个常量,后续的19个都可以这样分析完成但是Oracle公司给我们提供了一个专门用于分析class文件字节码的工具:Javap 具体如下图
通过javap解析出的常量池
从图中可知计算机已经帮我们吧整个常量池都计算了出来。

3.4 access_flage 访问标志

在常量池结束后,紧接着的两个字节代表访问标志 access_flags,这个标志用于识别一些类或者接口层测的访问信息,比如:是类还是接口,是否定义为public,是否定义为abstract类型,如果是类的话是否被声明为final等等下面是具体的含义表

访问标准的具体含义表
在这里具体值为0x0021 0x0021为0x0021和0x0001的与运算结果,为啥要进行与运算呢,因为access_flags 中共有16个标志位可以使用,当前只定义了8个,没有使用到的标志要求为0,Demo是一个普通java类,不是接口、枚举、或者注解,只有public关键字修饰

3.5 this_class & super_class &interaces 类索引、父类索引与接口索引集合

this_class(类索引)、super_class(父类索引)都是一个u2类型的数据,而interfaces(接口索引集合)是一组u2类型的数据的集合class文件由这三个数据来确定这个类的继承关系
Demo的class文件
0x0001、0x0003、0x0000 分别表示类索引为1 、父类索引为3、接口索引集合大小为0
通过前面用javap算出来的常量池可以知道
类索引为:com/baidu/test/Demo;
父类索引为: java/lang/Object;

3.6 field_info字段表集合

字段表用于描述接口或者类中声明的变量,但是不包括在方法内部声明的局部变量。可以包括的信息有:public、private、protected、static、final、volatile、transient、基本类型、对象、数组、字段名称
下图为字段表的格式
字段表结构
字段访问标注如下图
字段访问标志
Demo的class文件
0x0001 为fields_count
0x0002 为access_flags
0x0005 为name_index
0x0006 为descriptor_index

3.7 methods 方法表集合

方法表集合与字段表集合的结构完全一致,结构如下
在这里插入图片描述
在访问标志和属性集合的可选项中有所不同,下图为方法访问标志
在这里插入图片描述
有人会提出疑问,不知道方法中的代码去哪里了,方法中的Java代码经过编译器编译成字节码指令后存放到方法属性表的一个名为code的属性中了,在下面属性表会进行讲解在这里插入图片描述
0x0002:methods_count
0x0001:access_flags
0x0007:descriptor_index
0x0008:attribute_count
0x0009:name_index

3.8attribute_info属性表集合

为了能正确解析 class文件,《Java虚拟机规范(第二版)》中预定了9项虚拟机实现应当能识别的属性,而在最新的《java虚拟机规范(java SE 7)》版本中,预定义属性已经增加到了21项,见下图。

虚拟机规范预定义的属性
接下来对其中一些关键字段进行讲解
(1).code
Java程序方法体中的代码经过javac编译器处理之后,最终变为字节码指令存在code属性内。code属性表结构如下:
code属性表结构
attribute_name_index : 是项指向CONSTANT_Utf8_info 型常量的索引,常量值固定为“code”,他代表该属性的名称;
attribute_length:指示了属性的长度,由于属性名称索引与属性长度一共为6个字节,所以属性值的长度固定为整个属性表长度减去6个字节。
max_stack 代表了操作数栈深度的最大值,虚拟机运行的时候需要根据这个值来分配栈帧中的操作栈深度。
max_locals:代表了局部变量表所需的存储空间。
code_length:和code用来存储java源程序编译后生成的字节码指令。code_length 表示字节码的长度,code是用于存储字节码指令的一系列字节流。
code 属性是class文件中最重要的一个属性,如果把java程序中的信息分为代码和元数据两部分,那么在整个class文件中,code属性用于描述代码(方法体内的),所有的其他数据项目都用于描述元数据。
(2). exceptions属性
exception属性的作用列举方法中可能抛出的受查异常的(Checked Exceptions)也就是方法描述时在throws关键字后面列举的异常。它的结构见下表
exceptions属性表结构
(3).LineNumberTable 属性
LineNumberTable 属性用于描述java源代码行号与字节码行号之间的对应关系。属性表结构如下。
在这里插入图片描述
(4).LocalVariableTable属性
LocalVariableTable属性用于描述栈帧中局部变量表中的变量与java源码中定义的变量之间的关系。属性表结构见下图。
LocalVariableTable属性表结构
(6).SourceFile属性
SourceFile属性用于记录生成这个class文件的源码文件名称。结构见下图。
SourceFile属性表结构
(6).ConstantValue属性
ConstantValue属性的作用是通知虚拟机自动为静态变量赋值。只有被static修饰的变量才能使用这个属性。结构见下图。
ContantValue属性表结构
(7).InnerClasses属性
InnerClasses这个属性会在虚拟机类加载的字节码验证阶段被新类型检查验证其使用。结构见下表
InnerClasses属性表结构
(8).Depercated & Synthetic
Depercated & Synthetic 两个属性的属于标志类型的布尔属性,只存在有和没有的区别,没有属性值的概念。结构加下图
Depercated & Synthetic属性结构

4总结

class文件是java虚拟机执行引擎的数据入口,也是java技术体系的基础构成之一,了解class文件的结构对进一步了解虚拟机执行引擎有很重要的意义。

猜你喜欢

转载自blog.csdn.net/li_ya_kun/article/details/82805630