前言:
如今看官们对“java的class”大致比较关注,你们都需要知道一些“java的class”的相关资讯。那么小编在网上网罗了一些对于“java的class””的相关资讯,希望大家能喜欢,大家一起来了解一下吧!JAVA class文件结构
class字节码文件
严格按照顺序紧凑地排列没有添加任何分隔符
两种类型:
1.无符号数 :
u1、u2、u4、u8属于基本的数据类型,代表1个字节、2个字节、4个字节和8个字节的无符号数,用来描述:数字数据,常量索引,数量值,编码构成的字符串值
2._info表
由多个无符号数或者其他表作为数据项构成的复合数据类型
_count前置容量计数器:
描述多个同一类型数据项的数量,本身u2类型
连续的某一类型的数据称为这一类型的集合
魔数与Class文件的版本
前4个字节: 魔数(Magic Number)CAFEBABE,Class文件标识符
第5,6个字节:次版本号(Minor Version),标识技术预览版,大多为零
第7,8个字节:主版本号(Major Version),从45开始,高版本JDK能向下兼容以前版本,但不能运行以后版本的Class文件,即用的就java
版本号不能大于该值
常量池容量计数值(constant_pool_count):
u2类型,描述常量池中常量的数量
计数从1开始,第0项常量代表不引用任何一个常量池项目的含义
即代码有效常量: 计数值-1
其他表集合都是从0开始
常量池—常量表集合(constant_pool)
本身某一项常量info类型又由两个或三个无符号数组成
Class文件里的资源仓库,别的表数据引用常量池中的常量
主要存放两大类常量
字面量Literal:
1.文本字符串: 双引号中的字符串,也包括方法局部变量中的字符串 ----字符串常量池
2.Double,Integer,Long,Float包装类字段引用的数值,也包括方法中包装类局部变量中的
3.被声明为final的常量值,即final修饰基本数据类型及String直接指定字符串的字段是为常量,编译有ConstantValue修饰
注;包装类final字段不标识ConstantValue
符号引用SymbolicReferences:
当虚拟机做类加载时,将会从常量池获得对应的符号引用,再在类创建时或运行时解析、翻译到具体的内存地址之中
1.被模块导出或者开放的包
2.类和接口的全限定名(_Class_info) :
com/my/Test
3.字段的名称和描述符
(NameAndType、Fieldref) :
NameAndType = order:Lcom/bean/Order
Fieldref= Class.NameAndType
4.方法的名称和描述符
(NameAndType、Methodref) : NameAndType = get:()Ljava/lang/String Methodref= Class.NameAndType
5.方法句柄和方法类型
6.动态调用点和动态常量
顺序:
当前类全限定名 com/my/Test
当前父类全限定名 java/lang/Object
全局字段简单名称 变量名
全局字段类型描述符:
基本类型:首字母大写,boolean为Z
引用类型:L前缀加类型全限定名,如Ljava/lang/String
数组类型:如java.lang. String[][]为[[Ljava/lang/String
字段描述符:(字段简单名:字段类型描述符)
方法描述符:(参数类型描述符)返回类型描述符 如:([CII[CIII)I
常量标识 ConstantValue
常量字面量
<init>或<cinit>
()V
code
然后是全局字段引用的对象信息
对象class 或 字面量
对象初始化Methodref
Fieldref
NameAndType
LineNumberTable
LocalVariableTable
this
L当前类全限定名
再是方法简单名
方法类型 :()Ljava/lang/String
先初始化局部变量字面量或对象信息,基本数据类型除外
再局部变量名及类型
常量池中每一项常量都是一个表,即常量池是由其他info表数据项构成的复合数据,每个info常量类型由2个或3个无符号数构成
截至JDK 13,常量池中分别有17种不同类型的常量,结构数据皆不同
共同的特点,表结构第一位用一个u1类型的标志位tag,来代表当前常量属于哪种常量类型
CONSTANT_Utf8_info:Utf8编码字符串常量
结构:
tag 标识常量类型,决定常量结构 u1
length Utf8编码字符串占用的字节长度 u2
注:2个字节描述长度,即最大值可为65535,超过将无法编译
bytes:length个长度的字节,扫描常量字符串内容
字面量常量类型
CONSTANT_Long_info:
CONSTANT_Float_info
CONSTANT_Double_info
CONSTANT_Integer_info
CONSTANT_String_info
可用命令查看
javap -verbose
访问标志(access_flags):
u2类型,识别一些类或者接口层次的访问信息,类信息以及修饰类型
类索引(this_class):
u2类型,确定这个类的全限定名,指向类描述符常量
父类索引(super_class):
u2类型,确定这个类的父类的全限定名,不允许多重继承,只有一个,java.lang.Object除外
接口计数器(interfaces_count):
接口索引入口u2类型数据,表示接口索引表的容量
接口索引集合(interfaces):
一组u2类型数据的集合,描述这个类实现了哪些接口,从左到右排列在接口索引集合中
字段表集合(field_info):
描述接口或者类中声明的变量,包括类级变量以及实例级变量,但不包括在方法内部声明的局部变量,不包括从超类或者父接口中继承而来的字段
Java语言中:字段不能重名
对于字节码来讲,如果两个字段的描述符不一致即类型不同,那字段重名就是合法的,这与Java语言不一样
字段计数器(fields_count):
字段表入口u2类型数据,表示字段表的容量
结构:
access_flags:字段修饰符,u2类型
name_index:字段简单名称,对常量池的引用
descriptor_index:字段的描述符即字段的数据类型符号,对常量池的引用
字段属性表
方法表集合:与字段表集合结构一致
描述接口或者类中声明的方法,但不会出现来自父类的方法信息,可能会有编译器自动添加的方法,如类构造器“<clinit>”方法及实例构造器“<init>”方法
Java语言中:方法返回类型不能作为判断方法重载的依据,条件:方法名相同,参数不同包括顺序(特征签名不同)
对于字节码来讲,如果两个方法有相同的名称和特征签名(参数),但返回值不同,就是合法的,这与Java语言不一样
方法计数器_count:
入口u2类型数据,表示方法表的容量即有多少个方法
结构:
access_flags:方法修饰符,u2类型
name_index:方法简单名称,对常量池的引用
descriptor_index:方法的描述符即()L,对常量池的引用
attributes_count
属性表集合(attributes)
属性表集合(attribute_info)
在字段表、方法表中,不要求各个属性表具有严格顺序,只要不与已有属性名重复,会忽略不认识的属性
1. Code属性
方法体中的代码经过Javac编译器处理后,最终变为字节码指令存储在Code属性内,在方法表的属性集合之中,接口或抽象类中的方法不存在Code属性
结构:
attribute_name_index:
u2类型,该属性的属性名称,指向_Utf8_info型常量的索引,该常量值固定为“Code”
attribute_length:
u4类型,属性值的长度,即固定为整个属性表长度减去6个字节
max_stack:
u2类型,操作数栈(Operand Stacks)深度的最大值,虚拟机运行的时候需要根据这个值来分配栈帧(Stack Frame)中的操作栈深度
max_locals:
u2类型,局部变量表所需的存储空间,单位Slot,可以重用,超出局部变量的作用域可重分配,javac编译器根据变量的作用域分配Slot给各个变量使用,然后计算出max_locals的大小
byte、char、float、int、short、boolean和returnAddress等长度不超过32位的数据类型,每个局部变量占用1个Slot
double和long这两种64位的数据类型则需要两个Slot来存放
局部变量表存放:
方法参数,实例方法中的隐藏参数“this”,显式异常处理器的参数,方法体中定义的局部变量,及return隐式变量
code_length:
u4类型,字节码长度,最大值可以达到2的32次幂-1,但虚拟机规范中明确限制一个方法不允许超过65535条字节码指令,即它实际只使用了u2的长度, 超出将因为方法生成字节码超长而导致编译失败
code:
存储字节码指令的一系列字节流,code_length个长度,u1类型,2的1*8次幂=0-255即共可表达256个指令
显式异常处理表:
处理方法中Java异常及finally处理的跳转
Exceptions属性:
在方法表中与Code属性平级,描述方法声明的异常,即throws关键字后面列举的异常
number_of_exceptions:
u2,方法可能抛出number_of_exceptions种受查异常
exception_index_table:
u2,每一种受查异常指向常量池中_Class_info型常量的索引,代表了该受查异常的类型
LineNumberTable属性
描述Java源码行号与字节码行号(字节码的偏移量)之间的对应关系
Javac中使用-g:none或-g:lines选项来取消或生成这项信息,默认生成
影响:
抛出异常时,堆栈中将不会显示出错的行号,并且在调试程序的时候,也无法按照源码行来设置断点
line_number_table:数量为line_number_table_length、类型为line_number_info的集合
line_number_info表包括
start_pc: u2类型,字节码行号
line_number: u2类型,Java源码行号
LocalVariableTable/LocalVariableTypeTable属性
描述栈帧中局部变量表中的变量与Java源码中定义的变量之间的关系
Javac中使用-g:none或-g:vars选项来取消或生成这项信息,默认生成
影响:
当其他人引用这个方法时,所有的参数名称都将会丢失,IDE将会使用诸如arg0、arg1之类的占位符代替原有的参数名,对代码编写带来较大不便,而且在调试期间无法根据参数名称从上下文中获得参数值
local_variable_info:
一个栈帧与源码中的局部变量的关联
结构:
start_pc:
某个局部变量的生命周期开始的字节码偏移量
length:
某个局部变量作用范围覆盖的长度
name_index:
局部变量的名称,指向常量池中_Utf8_info型常量
descriptor_index/Signature:
局部变量的描述符
index/Slot:
局部变量在栈帧局部变量表中Slot的位置,当变量数据类型是64位类型时(double和long),占用的Slot为index和index+1两个
SourceFile属性,定长属性
记录生成这个Class文件的源码文件名称
Javac的-g:none或-g:source选项来关闭或要求生成这项信息.默认类名和文件名一致,内部类除外
影响:
当抛出异常时,堆栈中将不会显示出错代码所属的文件名
sourcefile_index:
指向常量池中_Utf8_info型常量的索引,值是源码文件的文件名
ConstantValue属性:
通知虚拟机自动为静态变量赋值
虚拟机对类变量和实例变量赋值的方式和时刻不同
类变量:
1.类构造器<clinit>方法中
只使用static来修饰的字段
2.使用ConstantValue属性
使用final和static来修饰或final修饰,且是基本类型或者String,就生成ConstantValue属性来进行初始化
实例变量:
在实例构造器<init>方法中进行
结构:
attribute_length:
u2,值固定为2
constantvalue_index:
u2,指向一个字面量常量索引
InnerClasses属性:
记录内部类与宿主类之间的关联
number_of_classes:记录多少个内部类信息
inner_classes_table:数量为number_of_classes、类型为inner_classes_info的集合
inner_class_info_index:
内部类符号引用,指向常量池中_Class_info型常量的索引
outer_class_info_index:
宿主类的符号引用
inner_name_index:
内部类的名称,指向常量池中_Utf8_info型常量的索引,匿名内部类,值为0
inner_class_access_flags:
内部类的访问标志,类似于类的access_flags
Deprecated及Synthetic属性
标志类型的布尔属性,只存在有和没有的区别,没有属性值的概念
Deprecated:
表示某个类、字段或者方法,已经被程序作者定为不再推荐使用
Synthetic:
字段或者方法并不是由Java源码直接产生,由编译器自行添加的
attribute_length数据项的值必须为0x00000000,因为没有任何属性值需要设置
StackMapTable属性
Signature属性
BootstrapMethods属性
标签: #java的class