龙空技术网

JAVA class文件结构

老干部快上车 124

前言:

今天朋友们对“javac后没有class文件”可能比较关切,看官们都想要学习一些“javac后没有class文件”的相关内容。那么小编也在网上汇集了一些关于“javac后没有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属性

标签: #javac后没有class文件