俺去也电影,毛骗第一季,北京德翰集团董事长
class文件包含了java虚拟机指令集 和 符号表 以及若干其他辅助信息.
class文件是一组以8位字节为基础单位的二进制字节流
各个数据项按照顺序紧凑的排列在class文件中,中间没有任何分隔符号
class文件采用类似 c结构体的格式存储数据
数据类型只有两种
无符号数 和 类c结构体的 表 表是由无符号数或者其他的表构成的
整个class文件就是一张表
无论无符号数还是表,当需要描述同一类型但数量不定的多个数据时,经常会使用一个前置的容量计数器用于指示接下来的数据个数,然后是若干个连续的数据项
class文件主要内容为: 类本身的信息 字段 方法 常量池 以及方法中的code属性 再就是一些相关的辅助信息
类本身的信息类本身有一些必备的描述信息,比如类名 访问修饰符 继承关系等
字段用于描述接口或者类中声明的变量
字段包括类变量以及实例变量,不包括局部变量 他有访问标志 名称 描述符信息
方法用于描述方法表信息 类似字段 也有访问标志 名称 描述符信息
常量池可以理解为class文件的资源仓库,所以他是与其他项目关联最多的数据类型
主要是两大类: 字面量 以及符号引用
字面量接近java语言层面的常量概念 比如文本字符串 声明为final常量的值
符号引用包括:
类和接口的全限定名
字段的名称和描述符
方法的名称和描述符
虚拟机加载class文件的时候动态链接,所以class文件中不会保存方法的最终内存布局, 还需要转换
虚拟机运行时从常量池中获得对应的符号引用,然后在创建或者运行时解析翻译到具体的内存地址中
code属性存放的java方法的内容,位于方法method_info 内
存放的是java方法经过编译器编译成的字节码指令 说白了存放的就是代码的编译后形式
概述:
class文件作为jvm的"机器语言" 主要包括两部分的信息,基础信息以及附加信息
基础信息为源代码中呈现的信息
类自身信息/字段/方法用于描述源代码中的类/字段/方法
常量池中保存了资源信息,比如字段的名字 方法的描述符等
方法中的code属性保存了方法中的代码的执行逻辑
额外信息为虚拟机执行过程中或者字节码指令执行所需要的信息
为了保证虚拟机能够正确的加载class文件
另外虚拟机加载类还需要做一些额外的工作比如校验信息等
字节码指令的执行可能还需要一些额外的信息
这些额外的信息通常也是保存在常量池中或者以属性的形式出现
|
struct 结构体名
{
类型名1 成员名1;
类型名2 成员名2;
.....
类型名n 成员名n;
};
|
struct student { char name[10]; char sex; int age; float score; };
ps: 所谓大小端 |
cp_info{ u1 tag; u1 info[ ] }
class文件的形式是一张巨大的表,是一个二进制字节流
只有两种数据表示形式 无符号数 以及 表(结构体 复合的数据结构)
各个数据项严格的按照顺序存放,之间没有填充或者对齐,这也是为何编译后代码如此紧凑的原因之一
基本数据类型为: u1 u2 u4 u8
|
classfile { u4 magic; u2 minor_version; u2 major_version; u2 constant_pool_count; cp_info constant_pool[constant_pool_count-1]; u2 access_flags; u2 this_class; u2 super_class; u2 interfaces_count; u2 interfaces[interfaces_count]; u2 fields_count; field_info fields[fields_count]; u2 methods_count; method_info methods[methods_count]; u2 attributes_count; attribute_info attributes[attributes_count]; }
public class helloworld { private int x; private string y; public void fun() { } public static void main(string[] args) { system.out.println("hello world"); } }
第一项 u4 magic
复合class文件魔数设置0xcafebabe
|
第二项 u2 minor_version 第三项 u2 major_version 所以说 主版本号为 52(34是十六进制) 次版本号为0 与javap解析后的数据吻合 |
第四项 u2 constant_pool_count 十六机制27 十进制39 可以看到javap解析后的constant pool:中总共有从#1 到 #38 常量池计数器constant_pool_count的值等于常量表中的成员数加1 常量池标的索引值只有大于0 且小于constant_pool_count时才有效 所以此处解析也是对的 |
第五项 cp_info constant_pool[constant_pool_count-1] 他是常量池 常量池表中的所有项目的格式为 cp_info{ u1 tag; u1 info[];
具体形式由tag的值决定 因为常量池计数为39 常量池中个数为[constant_pool_count-1]所以是38 也就是接下来会有38个 {u1 和 多个u1 } 这种形式的数据组合 第一个tag tag = 7 表示 constnt_class 结构为 constant_class_info{ u1 tag; u2 name_index;
name_index 的值是常量池中的一个索引 他指向的是2号索引 也就是 在接下来的一个u1 是下一个常量池数据项的tag tag 为1 表示constant_utf8 他的结构为 constant_utf8_info{ u1 tag; u2 length; u1 bytes[length];
表示长度为10 在接下来是数组的起始地址,长度为10 那么就是10个u1 我们翻一下ascii码表,对照下十六进制与字符 48 h 65 e 6c l 6c l 6f o 57 w 6f o 72 r 6c l 64 d 也就是helloworld 这其实就是我们的类名 |
classfile { u4 magic;//唯一作用是确定这个文件是否为一个能被虚拟机所接受的class文件。魔数值固定为0xcafebabe,不会改变 u2 minor_version;//唯一作用是确定这个文件是否为一个能被虚拟机所接受的class文件。魔数值固定为0xcafebabe,不会改变 u2 major_version;//主版本号 u2 constant_pool_count;//常量池计数 值等于常量池表中的成员个数加1 cp_info constant_pool[constant_pool_count-1];//常量池 1~ constant_pool_count-1 为索引 u2 access_flags;//访问标志以及类型信息 u2 this_class;//当前类索引 指向常量池中一个constant_class_info u2 super_class;//父类索引 0 或者指向常量池中一个constant_class_info u2 interfaces_count;//直接超接口数量 u2 interfaces[interfaces_count];//接口表 u2 fields_count;//字段个数 static类变量或者非sttic的实例变量 不包括继承的 field_info fields[fields_count];//字段表 u2 methods_count;//方法个数 所有方法 但不包括继承而来的 method_info methods[methods_count];//方法表 u2 attributes_count;//属性个数 attribute_info attributes[attributes_count];/属性表 }
形式是
fieldtype
|
b | byte | [基本类型] 有符号的字节数组 |
c | char | [基本类型] 基本多语种平面中的unicode代码点 utf-16 |
d | double | [基本类型] 双精度浮点数 |
f | float | [基本类型] 单精度浮点数 |
i | int | [基本类型] 整型数 |
j | long | [基本类型] 长整数 |
s | short | [基本类型] 有符号短整数 |
z | boolean | [基本类型] 布尔值true/false |
l classname; | l classname; | [对象类型] classname类的实例 |
[ | reference | [数组类型] 一维数组 |
形式是
( {parameterdescriptor} ) returndescriptor
注意: {} 不是一部分,是想表达和数组似的,也可能是多个
|
名称 | 值 | |
acc_public | 0x0001 | 声明为public 包外访问 |
acc_final | 0x0010 | final 不允许子类 |
acc_super | 0x0020 | 调用invokespecial 需要处理父类 |
acc_interface | 0x0200 | 这是一个接口 |
acc_abstract | 0x0400 | abstract 抽象的不能被实例化 |
acc_synthetic | 0x1000 | class文件并非由java源代码生成 |
acc_annotation | 0x2000 | 注解 |
acc_enum | 0x4000 | 枚举 |
主要分为两类 字面量 符号引用
字面量类似java语言层面的含义 文本字符串 声明为final 的常量值
符号引用包括:
类和接口的全限定名
字段的名称和描述符
方法的名称和描述符
常量池包含了class文件结构及其子结构中引用的所有的,字符串常量,类或者接口名,字段名,以及其他常量
|
基本数据类型,比如 int long的描述形式,
虽然class文件是二进制字节流,最小为u1 但是这些基本数据类型在逻辑意义上来说,才是最小的描述单位
|
用于表述, 用于描述各个部分包含的逻辑内容的表 "结构体" 复合形式的数据类型结构
|
中间的映射结构表 相当于数据库中的中间关系表
|
cp_info{ u1 tag; u1 info[]; }
constant_class | 7 |
constant_fieldref | 9 |
constant_methodref | 10 |
constant_interfacemethodref | 11 |
constant_string | 8 |
constant_integer | 3 |
constant_float | 4 |
constant_long | 5 |
constant_double | 6 |
constant_nameandtype | 12 |
constant_utf8 | 1 |
constant_methodhandle | 15 |
constant_methodtype | 16 |
constant_invokedynamic | 18 |
字符串常量 |
constant_utf8_info {
u1 tag;
u2 length;
u1 bytes[length];
}
|
tag是constant_utf8 1 字符串采用改进过的utf-8编码表示 接下来是编码后的字符串占用字节数以及字符串 class文件中的方法字段名称都是此类型 |
网友评论