一、 java class 字节码概述以及Java字节码结构
java类型识别:Java类是编译器生成字节码有其特定的组织规律,Java虚拟机在加载类时,对编译期生成的字节码信息按照固定的格式进行解析,一步一步解析出来字节码中所存在的类型结构信息,从而在运行期完全还原出原始的Java类的全部结构 。
class的字节概述:每一个Java类被编译之后生成一个对应的.class 字节码文件,需要明白jvm加载java类的原理,首先需要知道java类被编译之成的.class格式文件结构。下面通过实例代码来描述字节码的组成格式。
一、idea中实例查看
1、首先我们在ida中创建一个项目,demo,然后 编译一下,如下图所示:
以上文件就是一个spring boot 项目的一个程序入口带有main 方法的类
2、查看编译之后的字节码文件:通过在ida中安装HexView插件查看(HexView使用,请翻看另一篇安装HexView),
3、通过反编译之后的class文件,做如下对比:
通过以上两个文件前后对比,我们发现编译后的文件,自动加上了默认的构造该函数
二、class 文件构成基础
1、class文件构成基础
在class字节码文件中,数据都是以二进制流的形式存储。字节流都安装规定的顺序排序,字节码之间不存在任何空袭,对于超过8位的数据,按照Big-Endian(大端)的顺序存储,即:低地址存放高有效字节,反之小端(little endian):低字节存放地有效字节。
2、class 文件的10个组成结构
class字节码文件采用类似c语言的结构体存储数据,主要分以下
(1),我们来说明一下:class文件只有两种数据类型:无符号数
和表
。如下表所示
数据类型 | 定义 | 说明 |
无符号 | 无符号数可以用来描述数字、索引引用、数量值或按照utf-8编码构成的字符串值。 | 其中无符号数属于基本的数据类型。 以u1、u2、u4、u8来分别代表1个字节、2个字节、4个字节和8个字节 |
表 | 表是由多个无符号数或其他表构成的复合数据结构。 | 有的表都以“_info”结尾。 由于表没有固定长度,所以通常会在其前面加上个数说明。 |
(2)、以下就是字节码结构表
类型 | 名称 | 说明 | 长度(字节) |
u4 | magic | 魔数,识别Class文件格式 | 4 |
u2 | minor_version | 副版本号 | 2 |
u2 | major_version | 主版本号 | 2 |
u2 | constant_pool_count | 常量池计算器 | 2 |
cp_info | constant_pool | 常量池 | n |
u2 | access_flags | 访问标志 | 2 |
u2 | this_class | 类索引 | 2 |
u2 | super_class | 父类索引 | 2 |
u2 | interfaces_count | 接口计数器 | 2 |
u2 | interfaces | 接口索引集合 | 2 |
u2 | fields_count | 字段个数 | 2 |
field_info | fields | 字段集合 | n |
u2 | methods_count | 方法计数器 | 2 |
method_info | methods | 方法集合 | n |
u2 | attributes_count | 附加属性计数器 | 2 |
attribute_info | attributes | 附加属性集合 | n |
一个class字节码文件主要由以下10部分组成:
1、MaginNamber
2、Version
3、Constant_pool
4、Access_flag
5、This_class
6、Super_class
7、Interfaces
8、Fields
9、Methods
10、Attributes
三、二进制文件解读,如下图所示:
1、MaginNamber 即魔数,是用来标志class文件的,位于每一个java class 文件的最前面4个字节,值固定为0xCAFEBABE不变。虚拟机加载文件时会先检查这4个字节,如果不是0xCAFEBABE,则虚拟机拒绝加载该文件,这样就可以防止加载非class文件而造成虚拟机奔溃。
2、Version 即版本号,字段由2个长度为2个字节的字段组成,分别是Major Version 和 Minor Version,代表当前class文件的主版本号和次版本号 。不同的虚拟机支持Java class 文件的版本范围是不同的,所以在加载class文件之前可以先看看该class文件是否为当前虚拟机支持范围之内的,避免加载不支持的class文件。(高版本兼容低版本,反转不支持)
3、Constant_pool 即常量池,是从class文件的第9个字节开始。首先是2个字节(第9、第10两个字节)的长度字段constant_pool_count,表名常量池包含了多少个常量。接下来是二进制信息描述[constant_pool_conut-1]个常量,里面放的是字面常量和符号引用。
字面常量主要包含文本串以及被声明final的常量。
符号引用包含类和接口的全局限定名、字段的名称和描述符、方法的名称和描述符。
4、Access_flag,主要保存当前类的访问权限。
5、This_cass,主要保存当前类的全局限定名在常量池的索引。
6、Super_class,主要保存当前类的父类的全局限定名在常量池里的索引。
7、Interfaces,主要保存当前类的接口列表,包含两部分内容:interfaces_count和interfaces[interfaces_count]
interfaces_count指的是当前类实现的接口数目。
interfaces[]是包含interfaces_count 个接口的全部限定名的索引的数组。
8、Fields,主要保存当前类的成员列表,包含两部分内容:fields_count 和 fields[fields_count ].
fields_count 是类变量和实例变量字段的数量总和。
field[]是包含字段详细信息列表。
9、Methods,主要保存当前类的方法列表,包含两部分内容:Methods_count 和 Methods[Methods_count].
Methods_count是该类或者接口显式定义的方法的数量。
Methods[]是包含方法信息的一个详细列表。
10、Attributes,主要保存当前类attribute列表,包含Attributes_count 和Attributes[Attributes_count].
好了,暂时就先学习到这吧,眼睛都看晕了