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的内容
screenshot
同时使用UE打开class文件
screenshot
我们来一起看下ClassFile结构
screenshot
前4个字节为魔数,也就是0xCAFEBABE,这里都是十六进制
screenshot
魔数后2个字节为副版本号,这里副版本号是0
screenshot
主版本号0x0033,转为十进制,主版本号是51 标示当前class是通过jdk 1.7编译的,0x32是jdk1.6 0x31是jdk1.5
screenshot
这两个字节是常量池计数器,常量池的数量为0x001A,转为十进制是26,也就是说常量池索引为1~26
screenshot

从常量池开始

常量池计数器后面紧跟着就是常量池的内容
所有的常量池项都具有如下通用格式:

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; 
}

screenshot

screenshot
后面的0x07对应tag找到是CONSTANT_Class,标示接下来的是一个class的信息。后面的 00 02 是class的name_index 标示指向常量池的第二个常量。我们再看第二个常量
screenshot
第二个常量是01开头,我们查看常量类型表中对应是Utf-8,再按照utf-8的结构,后面的00 0A代表了这个utf-8的长度这里长度转换为10进制是11,后面紧跟着utf-8的实际内容
screenshot
screenshot
再后面0x 07,是常量池的下一个产量,也是一个class信息,后面跟00 04,name_index执行常量池的
第4个常量。
screenshot
第4个常量又是utf-8,后面长度为 0x10 十进制为16,接下来的为实际内容
screenshot
接下来都可以按照此方法分析。
直观结果可以通过javap指令查看
screenshot

screenshot
常量池后面紧跟的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个字节
screenshot
这里为00 01,指向常量池中第一个常量,之前我们分析过常量池中第一个常量为Class类型,内容指向第二个常量UTF-8的HelloWorld。
标示当前名为HelloWorld

父类索引

也是2个字节
screenshot
指向常量中第三个常量,对应内容为java/lang/Object

接口数量

screenshot
表示接口数量为0
screenshot

字段表集合

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
screenshot
descriptor_index指向常量池第6个变量,为Ljava/lang/String类型
attributes_count(属性计数器,占2字节,0x0000,所以该字段没有额外需要描述的信息)

方法集合

screenshot
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
screenshot
screenshot
attributes_count 为 00 01标示这个方法的属性表集合中有一个属性。属性名称为接下来2位0x0009,指向常量池中第9个常量:Code
接下来4位为 00 00 00 3D标示Code属性值的字节长度为3D,接下来为00 02标示该方法的操作数栈的深度最大值为2.
00 01标示该方法的局部变量占用空间为1.
screenshot
接下来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,接着开始第二个方法。

相关文章
|
7月前
|
存储 Oracle Java
JVM中Class文件结构详解
JVM中Class文件结构详解
144 0
|
2月前
|
SQL 缓存 Java
JVM知识体系学习三:class文件初始化过程、硬件层数据一致性(硬件层)、缓存行、指令乱序执行问题、如何保证不乱序(volatile等)
这篇文章详细介绍了JVM中类文件的初始化过程、硬件层面的数据一致性问题、缓存行和伪共享、指令乱序执行问题,以及如何通过`volatile`关键字和`synchronized`关键字来保证数据的有序性和可见性。
31 3
|
2月前
|
小程序 Oracle Java
JVM知识体系学习一:JVM了解基础、java编译后class文件的类结构详解,class分析工具 javap 和 jclasslib 的使用
这篇文章是关于JVM基础知识的介绍,包括JVM的跨平台和跨语言特性、Class文件格式的详细解析,以及如何使用javap和jclasslib工具来分析Class文件。
50 0
JVM知识体系学习一:JVM了解基础、java编译后class文件的类结构详解,class分析工具 javap 和 jclasslib 的使用
|
7月前
|
存储 Java 索引
《深入浅出Java虚拟机 — JVM原理与实战》带你攻克技术盲区,夯实底层基础 —— 吃透class字节码文件技术基底和实现原理(核心结构剖析)
《深入浅出Java虚拟机 — JVM原理与实战》带你攻克技术盲区,夯实底层基础 —— 吃透class字节码文件技术基底和实现原理(核心结构剖析)
77 0
|
7月前
|
存储 缓存 前端开发
JVM(二):Class加载机制
JVM(二):Class加载机制
|
7月前
|
存储 Java 编译器
JVM(一):Class文件格式
JVM(一):Class文件格式
|
Java 关系型数据库 MySQL
阿里面试官(性能优化):描述一下jvm加载class文件的原理机制?
相信很多人对于性能优化都不陌生,为了获得更好的系统性能,或者是为了满足不断增加的业务需求。 都需要用到我们的性能调优。所以性能优化在面试中出现的频率特别高 楼主自认为自己对性能优化相关知识有很多了解,而且因为最近在找工作面试,所以单独复习了很多关于索引的知识。
|
存储 Java 编译器
jvm之.class文件解读(下)(二)
jvm之.class文件解读(下)(二)
|
存储 Java 编译器
jvm之.class文件解读(下)(一)
jvm之.class文件解读(下)
|
存储 安全 前端开发
jvm之.class文件解读(上)
jvm之.class文件解读(上)