JVM Class详解之一
首先看Class中包含哪些信息简单的说所有Java文件中有的信息class文件都有,编译器帮我们将java文件转化成了JVM能看懂的class格式而已
Class 概述
Class文件是一组以8位字节为基础的二进制流,各个数据项目按照严格顺序紧凑排列在Class文件中。
所有的16位,32位,64位长度的数据将被构造成2个,4个,8个字节单位来标示。
ClassFile结构
| 类型 | 名称 | 数量 |
|---|---|---|
| u4 | magic | 1 |
| u2 | minor_version | 1 |
| u2 | major_version | 1 |
| u2 | constant_pool_count | 1 |
| cp_info | constant_pool | constant_pool_count-1 |
| u2 | access_flags | 1 |
| u2 | this_class | 1 |
| u2 | super_class | 1 |
| u2 | interfaces_count | 1 |
| u2 | interfaces | interfaces_count |
| u2 | fields_count | 1 |
| field_info | fields | fields_count |
| u2 | methods_count | 1 |
| method_info | methods | methods_count |
| u2 | attributes_count | 1 |
| attribute_info | attributes | attributes_count |
class格式说明
- magic:魔数,魔数的唯一作用是确定这个文件是否为一个能被虚拟机所接受的Class文件。魔数值固定为0xCAFEBABE
- minor_version、major_version: 分别为Class文件的副版本和主版本
- constant_pool_count: 常量池计数器,constant_pool_count的值等于constant_pool表中的成员数加1
- constant_pool[]: 常量池,constant_pool是一种表结构,它包含Class文件结构及其子结构中引用的所有字符串常量、类或接口名、字段名和其它常量。常量池不同于其他,索引从1开始到constant_pool_count -1
- access_flags: 访问标志,access_flags是一种掩码标志,用于表示某个类或者接口的访问权限及基础属性
- this_class: 类索引,this_class的值必须是对constant_pool表中项目的一个有效索引值
- super_class: 父类索引
- interfaces_count: 接口计数器,interfaces_count的值表示当前类或接口的直接父接口数量
- interfaces[]: 接口表,interfaces[]数组中的每个成员的值必须是一个对constant_pool表中项目的一个有效索引值,它的长度为interfaces_count
- fields_count: 字段计数器
- fields[]: 字段表,fields[]数组中的每个成员都必须是一个fields_info结构的数据项
- methods_count: 方法计数器
- methods[]: 方法表,methods[]数组中的每个成员都必须是一个method_info结构的数据项
- attributes_count: 属性计数器
- attributes[]: 属性表,attributes表的每个项的值必须是attribute_info结构
废话不多说HelloWorld搞起
public class HelloWorld
{
String str = "";
public String getStr()
{
return str;
}
public void setStr(String str)
{
this.str = str;
}
}
编译成class文件以后,只用javap -verbose HelloWorld.class 指令可以查看当前class的内容
同时使用UE打开class文件
我们来一起看下ClassFile结构
前4个字节为魔数,也就是0xCAFEBABE,这里都是十六进制
魔数后2个字节为副版本号,这里副版本号是0
主版本号0x0033,转为十进制,主版本号是51 标示当前class是通过jdk 1.7编译的,0x32是jdk1.6 0x31是jdk1.5
这两个字节是常量池计数器,常量池的数量为0x001A,转为十进制是26,也就是说常量池索引为1~26
从常量池开始
常量池计数器后面紧跟着就是常量池的内容
所有的常量池项都具有如下通用格式:
cp_info
{
u1 tag;
u1 info[];
}
CONSTANT_Class_info
{
u1 tag;
u2 name_index;
}
CONSTANT_Fieldref_info
{
u1 tag;
u2 class_index;
u2 name_and_type_index;
}
CONSTANT_Methodref_info
{
u1 tag;
u2 class_index;
u2 name_and_type_index;
}
CONSTANT_InterfaceMethodref_info
{
u1 tag;
u2 class_index;
u2 name_and_type_index;
}
CONSTANT_NameAndType_info
{
u1 tag;
u2 name_index;
u2 descriptor_index;
}
CONSTANT_Utf8_info
{
u1 tag;
u2 length;
u1 bytes[length];
}
CONSTANT_MethodHandle_info
{
u1 tag;
u1 reference_kind;
u2 reference_index;
}


后面的0x07对应tag找到是CONSTANT_Class,标示接下来的是一个class的信息。后面的 00 02 是class的name_index 标示指向常量池的第二个常量。我们再看第二个常量
第二个常量是01开头,我们查看常量类型表中对应是Utf-8,再按照utf-8的结构,后面的00 0A代表了这个utf-8的长度这里长度转换为10进制是11,后面紧跟着utf-8的实际内容

再后面0x 07,是常量池的下一个产量,也是一个class信息,后面跟00 04,name_index执行常量池的
第4个常量。
第4个常量又是utf-8,后面长度为 0x10 十进制为16,接下来的为实际内容
接下来都可以按照此方法分析。
直观结果可以通过javap指令查看

常量池后面紧跟的2个字节是Access Flag,这个表示用于标示类或接口层次的访问信息,如这个Class是类还是接口,是否为public类型,是否定义为abstrace类型。
标志名称 标志值 含义
ACC_PUBLIC 0x0001 是否为public类型
ACC_FINAL 0x0010 是否被声明为final,只有类可设置
ACC_SUPER 0x0020 是否允许使用invokespecial字节码指令,JDK1.2以后编译出来的类这个标志为真
ACC_INTERFACE 0x0200 标识这是一个接口
ACC_ABSTRACT 0x0400 是否为abstract类型,对于接口和抽象类,此标志为真,其它类为假
ACC_SYNTHETIC 0x1000 标识别这个类并非由用户代码产生
ACC_ANNOTATION 0x2000 标识这是一个注解
ACC_ENUM 0x4000 标识这是一个枚举
我们这里0021标示为public Class
接下来的是类索引,父类索引与接口索引集合
this_class,super_class,interfaces_count,interfaces
类索引
为2个字节
这里为00 01,指向常量池中第一个常量,之前我们分析过常量池中第一个常量为Class类型,内容指向第二个常量UTF-8的HelloWorld。
标示当前名为HelloWorld
父类索引
也是2个字节
指向常量中第三个常量,对应内容为java/lang/Object
接口数量

表示接口数量为0
字段表集合
00 01 标示字段数量为1
字段表的格式如下
| 类型 | 名称 | 数量 |
|---|---|---|
| u2 | access_flags | 1 |
| u2 | name_index | 1 |
| u2 | descriptor_index | 1 |
| u2 | attributes_count | 1 |
| attribute_info | attributes | attributes_coun |
accessFlags为 00 00 当时当前字段无修饰符
字段修饰符格式如下
| 标志名称 | 标志值 | 含义 |
|---|---|---|
| ACC_PUBLIC | 0x0001 | 字段是否为public |
| ACC_PRIVATE | 0x0002 | 字段是否为private |
| ACC_PROTECTED | 0x0004 | 字段是否为protected |
| ACC_STATIC | 0x0008 | 字段是否为static |
| ACC_FINAL | 0x0010 | 字段是否为final |
| ACC_VOLATILE | 0x0040 | 字段是否为volatile |
| ACC_TRANSIENT | 0x0080 | 字段是否为transient |
| ACC_SYNTHETIC | 0x1000 | 字段是否为编译器自动产生 |
| ACC_ENUM | 0x4000 | 字段是否为enum |
name_index为 00 05指向常量池中的第五个常量
第5个常量为str,变量名为str
descriptor_index指向常量池第6个变量,为Ljava/lang/String类型
attributes_count(属性计数器,占2字节,0x0000,所以该字段没有额外需要描述的信息)
方法集合

method_count: 00 03 有3个方法
methods:方法表集合
| 类型 | 名称 | 数量 |
|---|---|---|
| u2 | access_flags | 1 |
| u2 | name_index | 1 |
| u2 | descriptor_index | 1 |
| u2 | attributes_count | 1 |
| attribute_info | attributes | attributes_coun |
access flags的定义见下表
| 标志名称 | 标志值 | 含义 |
|---|---|---|
| ACC_PUBLIC | 0x0001 | 字段是否为public |
| ACC_PRIVATE | 0x0002 | 字段是否为private |
| ACC_PROTECTED | 0x0004 | 字段是否为protected |
| ACC_STATIC | 0x0008 | 字段是否为static |
| ACC_FINAL | 0x0010 | 字段是否为final |
| ACC_SYNCHRONIZED | 0x0020 | 字段是否为synchronized |
| ACC_BRIDGE | 0x0040 | 方法是否是由编译器产生的桥接方法 |
| ACC_VARARGS | 0x0080 | 方法是否接受不定参数 |
| ACC_NATIVE | 0x0100 | 字段是否为native |
| ACC_ABSTRACT | 0x0400 | 字段是否为abstract |
| ACC_STRICTFP | 0x0800 | 字段是否为strictfp |
| ACC_SYNTHETIC | 0x1000 | 字段是否为编译器自动产生 |
这里方法access flags 为 00 01 说明方法为public的
name_index为00 07,方法名指向常量中第7个常量方法名为, descriptor_index为常量池第8个常量()V

attributes_count 为 00 01标示这个方法的属性表集合中有一个属性。属性名称为接下来2位0x0009,指向常量池中第9个常量:Code
接下来4位为 00 00 00 3D标示Code属性值的字节长度为3D,接下来为00 02标示该方法的操作数栈的深度最大值为2.
00 01标示该方法的局部变量占用空间为1.
接下来4位00 00 00 0B 为机器编译生成字节码指令的长度为11,后面11个字节就是字节码指令(字节码指令可查询虚拟机字节码指令表),这里字节码指令长度用4个字节标示,所有字节码指令超长Class编译会失败的。
再接下来为 00 00标示Code属性异常表结合为空。
再后面为 00 02,,说明Code带有2个属性, 00 10即为Code属性第一个属性的属性名成指向常量池中第16个常量
接下来的00 00 00 0E 标示LinueNumberTable属性值所占字节长度为15.接下来2位 00 03标示该line number table中有3个line number table表,start pc为 00 00 line number第 00 01个为00 04 第 00 02个为 00 0A
再后面的 00 01又是第二个方法的access flags,接着开始第二个方法。
from: https://yq.aliyun.com/articles/7241?spm=5176.100239.blogcont37179.10.F6pHuW
- 顶
- 0
- 踩
JVM Class详解之一的更多相关文章
- [转]JVM指令详解(上)
作者:禅楼望月(http://www.cnblogs.com/yaoyinglong) 本文主要记录一些JVM指令,便于记忆与查阅. 一.未归类系列A 此系列暂未归类. 指令码 助记符 ...
- JVM内存详解-阅读笔记
- JVM结构详解
JVM 结构详解 JVM 结构图 程序计数器(PC 寄存器) 程序计数器的定义 程序计数器是一块较小的内存空间,是当前线程正在执行的那条字节码指令的地址.若当前线程正在执行的是一个本地方法,那么此时程 ...
- 一篇看懂JVM底层详解,利用class反编译文件了解文件执行流程
JVM之内存结构详解 JVM内存结构 java虚拟机在执行程序的过程中会将内存划分为不同的区域,具体如图1-1所示. 五个区域 JVM分为五个区域:堆.虚拟机栈.本地方法栈.方法区(元空间).程序计数 ...
- JVM组成详解
一.JVM 整体组成 JVM 整体组成可分为以下四个部分: 类加载器(ClassLoader) 运行时数据区(Runtime Data Area) 执行引擎(Execution Engine) 本地库 ...
- Java系列:JVM指令详解(上)(zz)
一.未归类系列A 此系列暂未归类. 指令码 助记符 说明 59:iastore 60:lload 6 //因为str ...
- JVM虚拟机详解
1. 什么是JVM? JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来 ...
- JVM指令详解(上)
指令码 助记符 说明 0x00 nop 什么都不做 0x01 ...
- Java中JVM虚拟机详解
1. 什么是JVM? JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来 ...
随机推荐
- jquery实现对div的拖拽功能
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- 阿里云API网关(16)客户端请求的https支持
网关指南: https://help.aliyun.com/document_detail/29487.html?spm=5176.doc48835.6.550.23Oqbl 网关控制台: https ...
- PyCharm设置仿sublime配色__Py版本2018.1
Talk is cheap~ Let's do this! 配色效果图: 在网上搜了一大圈,没有能看的一清二楚的,注意本次Pycharm版本是2018.1,如果是别的版本,基本设置也是大同小异~ 看图 ...
- Python系列-python内置函数
abs(x) 返回数字的绝对值,参数可以是整数.也可以是浮点数.如果是复数,则返回它的大小 all(iterable) 对参数中的所有元素进行迭代,如果所有的元素都是True,则返回True,函数等价 ...
- 1.2WEB API 跨域
详细请参考http://www.cnblogs.com/landeanfen/p/5177176.html 在项目上面使用Nuget安装 microsoft.aspnet.webapi.cors 在w ...
- Spring Cloud学习笔记-002
搭建Spring Cloud注册中心:Eureka 服务注册:在服务治理框架中,通常都会构建一个注册中心,每个服务单元向注册中心登记自己提供的服务,将主机与端口号.版本号.通信协议等一些附加信息告诉注 ...
- Linux 文件读写操作与磁盘挂载
文件读写 [文件描述符] Linux下,通常通过open打开一个文件,它然后返回给我们一个整数,通过这个整数便可以操作文件,这个整数我们称文件描述符(fd).对应被打开的文件,它也是一种系统资源,那么 ...
- 全球性WannaCry蠕虫勒索病毒感染前后应对措施
前言:针对WannaCrypt勒索病毒的讨论和技术文章是铺天盖地,大量的技术流派,安全厂家等纷纷献计献策,有安全厂家开发各种安全工具,对安全生态来说是一个好事,但对个人未必就是好事,我们国家很多用户是 ...
- How to preview html file in our browser at sublime text?
sublime preview html.md open In Browser what should we do if we want to preview html file in our bro ...
- [LeetCode] 4 Keys Keyboard 四键的键盘
Imagine you have a special keyboard with the following keys: Key 1: (A): Print one 'A' on screen. Ke ...