原文链接:/DLevin/archive//09/05/358033.html
小介:去年在读《深入解析JVM》的时候写的,记得当时还想着用自己的代码解析字节码的,最后只完成了一部分。现在都不知道还有没有保留着,貌似Apache有现成的BCEL工程可以做这件事。当时也只是为了学习。这份资料主要参考《深入解析JVM》和《Java虚拟机规范》貌似是1.2版本的,整理出来的。里面包含了一些自己的理解和用实际代码的测试。有兴趣的童鞋可以研究研究。嘿嘿。要有错误也希望能为小弟指点出来,感激不尽。:)
1.总体格式
2.格式详解
2.1magic
magic被称为“魔数”,用来标识.class文件的开头。所有合法的.class字节码都应该是该数开头,占4个字节。
2.2major_version.minor_version
major_version.minor_version合在一起形成当前.class文件的版本号,该版本号一般由编译器产生,并且由sun定义。如59.0。它们一起占4个字节。
2.3constant_pool
在Java字节码中,有一个常量池,用来存放不同类型的常量。由于Java设计的目的之一就是字节码需要经网络传输的,因而字节码需要比较紧凑,以减少网络传输的流量和时间。常量池的存在则可以让一些相同类型的值通过索引的方式从常量池中找到,而不是在不同地方有不同拷贝,缩减了字节码的大小。
每个常量池中的项是通过cp_info的类型来表示的,它的格式如下:
这里tag用来表示当前常量池不同类型的项。info中存放常量池项中存放的数据。
tag中表示的数据类型:
CONSTANT_Class_info(7)、
CONSTANT_Integer_info(3)、
CONSTANT_Long_info(5)、
CONSTANT_Float_info(4)、
CONSTANT_Double_info(6)、
CONSTANT_String_info(8)、
CONSTANT_Fieldref_info(9)、
CONSTANT_Methodref_info(10)、
CONSTANT_InterfaceMethodref_info(11)、
CONSTANT_NameAndType_info(12)、
CONSTANT_Utf8_info(1)、
注:在Java字节码中,所有boolean、byte、char、short类型都是用int类型存放,因而在常量池中没有和它们对应的项。
2.3.1CONSTANT_Class_info
用于记录类或接口名(used to represent a class or an interface)
注:在Java字节码中,类和接口名不同于源码中的名字,详见附件A.
2.3.2CONSTANT_Integer_info
用于记录int类型的常量值(represent 4-byte numeric (int) constants:)
2.3.3CONSTANT_Long_info
用于记录long类型的常量值(represent 8-byte numeric (long) constants:)
2.3.4CONSTANT_Float_info
用于记录float类型的常量值(represent 4-byte numeric (float) constants:)
几个特殊值:0x7f800000 => Float.POSITIVE_INFINITY、0xff800000 => Float.NEGATIVE_INFINITY、
0x7f800001 to 0x7fffffff => Float.NaN、0xff800001 to 0xffffffff => Float.NaN
2.3.5CONSTANT_Double_info
用于记录double类型的常量值(represent 8-byte numeric (double) constants:)
几个特殊值:0x7ff0000000000000L => Double.POSITIVE_INFINITY、
0xfff0000000000000L => Double.NEGATIVE_INFINITY
0x7ff0000000000001L to 0x7fffffffffffffffL => Double.NaN、
0xfff0000000000001L to 0xffffffffffffffffL => Double.NaN
2.3.6CONSTANT_String_info
用于记录常量字符串的值(represent constant objects of the typeString:)
2.3.7CONSTANT_Fieldref_info
用于记录字段信息(包括类或接口中定义的字段以及代码中使用到的字段)。
2.3.8CONSTANT_Methodref_info
用于记录方法信息(包括类中定义的方法以及代码中使用到的方法)。
2.3.9CONSTANT_InterfaceMethodref_info
用于记录接口中的方法信息(包括接口中定义的方法以及代码中使用到的方法)。
2.3.10CONSTANT_NameAndType_info
记录方法或字段的名称(name)和描述符(descriptor)(represent a field or method, without indicating which class or interface type it belongs to:)。
2.3.11CONSTANT_Utf8_info
记录字符串的值(represent constant string values. String content is encoded inmodified UTF-8.)
modifie
d UTF-8 refer to :
http://download.ora
/javase/1.4.2/docs/api/java/io/DataInputStream.html
2.4access_flags
指定类或接口的访问权限。
2.5this_class
this_class是指向constant pool的索引值,该值必须是CONSTANT_Class_info类型,指定当前字节码定义的类或接口。
2.6super_class
super_class是指向constant pool的索引值,该值必须是CONSTANT_Class_info类型,指定当前字节码定义的类或接口的直接父类。只有Object类才没有直接父类,此时该索引值为0。并且父类不能是final类型。接口的父类都是Object类。
2.7interfaces
interfaces数组记录所有当前类或接口直接实现的接口。interfaces数组中的每项值都是一个指向constant pool的索引值,这些值必须是CONSTANT_Class_info类型。数组中接口的顺序和源代码中接口定义的顺序相同。
2.8fields
fields数组记录了类或接口中的所有字段,包括实例字段和静态字段,但不包含父类或父接口中定义的字段。fields数组中每项都是field_info类型值,它描述了字段的详细信息,如名称、描述符、字段中的attribute等。
注:fields中的项目和CONSTANT_Fieldref_info中的项目部分信息是相同的,他们主要的区别是CONSTANT_Fieldref_info中的项目不仅包含了类或接口中定义的字段,还包括在字节码中使用到的字段信息。不过这里很奇怪,为什么field_info结构中不把name_index和descriptor_index合并成fieldref_index,这样的class文件不是更加紧凑吗??不知道这是sun因为某些原因故意这样设计还是这是他们的失误??
2.8.1字段访问权限
注:接口中的字段必须同时设置:ACC_PUBLIC、ACC_STATIC、ACC_FINAL
2.8.2ConstantValue Attribute(JVM识别)
每个常量字段(final,静态常量或实例常量)都包含有且仅有一个ConstantValue Attribute。ConstantValue Attribute结构用于存储一个字段的常量值。
对一个静态常量字段,该常量值会在类或接口被初始化之前,由JVM负责赋给他们,即它在任何静态字段之前被赋值。
对一个非静态常量字段,该值会被虚拟机忽略,它的赋值由生成的实例初始化函数(<init>)实现。如类:
classA {
publicstaticfinalintfa= 10;
publicfinalintfa2= 30;
privatestaticintsa= 20;
static{
sa= 30;
}
}
生成的字节码如下:
// Compiled from Test.java (version 1.6 : 50.0, super bit)
class org.levin.insidejvm.miscs.staticinit.A {
public static final int fa = 10;
public final int fa2 = 30;
private static int sa;
static {};
0bipush 20
2putstatic org.levin.insidejvm.miscs.staticinit.A.sa : int [16]
5bipush 30
7putstatic org.levin.insidejvm.miscs.staticinit.A.sa : int [16]
10return
public A();
0aload_0 [this]
1invokespecial java.lang.Object() [21]
4aload_0 [this]
5bipush 30
7putfield org.levin.insidejvm.miscs.staticinit.A.fa2 : int [23]
10return
2.8.3Synthetic Attribute
参考2.11.1
2.8.4Signature Attribute
参考2.11.2
2.8.5Deprecated Attribute
参考2.11.3
2.8.6RuntimeVisibleAnnotations Attribute
参考2.11.4
2.8.7RuntimeInvisibleAnnotations Attribute
参考2.11.5 于-12-19
如果觉得《Java字节码(.class文件)格式详解(一)》对你有帮助,请点赞、收藏,并留下你的观点哦!