java 类文件_关于Java类文件结构的详细介绍

部分摘自https://blog.csdn.net/u010963948/article/details/90080056

部分摘自https://blog.csdn.net/qq_42764468/article/details/103690188

在Java中,JVM可以理解的代码就叫做字节码(即扩展名为.class文件),它不面向任何特定的处理器,只面向虚拟机。Java语言通过字节码的方式,在一定程度上解决了传统解释性语言执行效率低的问题,同时又保留了解释性语言可移植的特点。所以Java程序运行时比较搞笑,而且,由于字节码并不针对一种特定的机器,因此,Java程序无须重新编译即可在多种不同的操作系统的计算机上运行。

Clojure(Lisp语言的一种方言)、Groovy、Scala等语言都是运行在Java虚拟机上。下图展示了不同的语言被不同的编译器编译成.class文件最终运行在Java虚拟机上,,class文件的二进制格式可以使用WinHex查看。

669385c02cb5129fef276afd6400d804.png

下面这个简单的Java代码,编译后生成Hello.class文件

packagecom.work.bytetest;public classHello {public static voidmain(String[] args) {

System.out.println("hello");

}

}

我们使用WinHex打开这个文件可以看到字节码的详细内容

0cc08f1104ee7eb115a5c90ef5dc8546.png

二、Class文件结构总结

根据Java虚拟机规范,类文件由单个ClassFile结构组成:

ClassFile {

u4 magic;//Class 文件的标志

u2 minor_version;//Class 的小版本号

u2 major_version;//Class 的大版本号

u2 constant_pool_count;//常量池的数量

cp_info constant_pool[constant_pool_count-1];//常量池

u2 access_flags;//Class 的访问标记

u2 this_class;//当前类

u2 super_class;//父类

u2 interfaces_count;//接口

u2 interfaces[interfaces_count];//一个类可以实现多个接口

u2 fields_count;//Class 文件的字段属性

field_info fields[fields_count];//一个类会可以有个字段

u2 methods_count;//Class 文件的方法数量

method_info methods[methods_count];//一个类可以有个多个方法

u2 attributes_count;//此类的属性表中的属性数

attribute_info attributes[attributes_count];//属性表集合

}

下面介绍一下Class文件结构涉及到的一些组件。

Class文件字节码结构示意图(原出处不知道)

2.1魔数

每个class文件的头四个字节成为魔数(Magic Number),它的唯一作用是确定这个文件是否为一个能被虚拟机接收的Class文件。

程序设计者很多时候都喜欢用一些特殊的数字表示固定的文件类型或者其他特殊的含义。

我们上面在WinHex中看到Hello.class文件的前四个字节是CA FE BA BE,每个类文件的前四个字节都是这个。

2.2Class文件版本

紧接着魔数的四个字节存储的是Class文件的版本号,第五和第六是次版本号,第七和第八是主版本号。

我们上面看到的次版本号是00 00,主版本号是00 34,16进制转成10进制应该就是52。

接下来就是常量池的数量:00 22,转成10进制就是34

一个Java类中定义的很多信息都是由常量池来维护和描述的,可以将常量池看做是class文件的资源仓库。比如说:Java类中定义的方法与变量信息,都是存储在常量池中。

常量池中主要存储两类常量:字面量与符号引用。字面量如文本字符串,java中声明为final的常量值等,而符号应用如类和接口的全局限定名,字段的名称和描述符。

常量池数组中的元素的个数=常量池数-1(其中0暂时不使用),我们这里就是33个,目的是满足某些常量池索引值的数据在特定情况下需要表达【不引用任何一个常量池】的含义;根本原因在于索引为0也是一个常量(保留常量),只不过它不位于常量表中,这个常量就对应于null值。

常量池数组紧跟在常量池数量之后,常量池数组与一般的数组不同的是,常量池数组中不同元素的类型,结构都是不同的,长度当然也不同;但是每一种元素的第一个数据都是一个u1类型,改自己是标志位,占据一个字节。jvm在解析常量池时,会根据这个u1类型来获取元素的具体类型。

下面根据使用WinHex软件显示的Hello.class在计算机磁盘中保存的16进制数据,反推Hello.class的内容:

第一个常量

bb05636cf7c35e9b476c334458b50fca.png

0A是10,

82fc2bf478df9df1670ea5e584e258aa.png

702e3681b3219fcacb83fbdfe9d983f3.png

第二个常量:

cc9c24f291007f67cdb72c849455cacb.png

9b20f6017b02a12aa34dbaf352f1c89b.png

3dab9885e3cf7976f98238916976f664.png

第三个常量:

faaa86c4bfcbf6991640eacfe645eda7.png

e9092abcafea61e53a1c188c05fec74f.png

5a10db0e23726e32d922bf4c79dce937.png

第四个常量:

b86d2f61442e6794b8d3c70a78583609.png

9764670f59dfb0acaec08dfc272d4745.png

de01bef106ccbbb9eae0f90638d191af.png

第五个常量:

86ad1f4ca6768e5e5a97255402f6541a.png

34ff31d3bb2c4e771a3a9f2284274991.png

497cb6fb795a78f62977866976639197.png

第六个常量:

48f2f616d44d10e2e54ad590a8fb3768.png

d4511c069f9a7f5164f3e877f5f12dd5.png

第七个常量为:

7005fc1027f2730b37b448c541ea64f8.png

6acf9ea8d1f65c6c5d902647ea6b5ec8.png

09a2b4c3363525c9a2ea3d67b3f67b6f.png

00 06转为10进制是6,那么后面6个字节是对应的值:

e30299580ea853aa701d0968ac3b94d9.png

第八个常量:

c52412eda2217ac33755061b5c919f9a.png

9cacaf7306474e12528d58eddd4f121e.png

00 03转为10进制就是3,表示接下来3个字节是对应的值:

818c885d93530ed329f8c331a64745ae.png

第九个常量:

45382ccdf476785531bb581ff39805d5.png

00 04转成10进制就是4,表示接下来4个字节是对应的值:

c3b2a8a0ad00ab6d528494940a9e0625.png

第十个常量:

37aa0423defe9aa3d0c4934336acbba7.png

对应的值:

fa5fd832981096beb0127caba624ff7d.png

第十一个常量:

fc4707afe923f1f50afaa9d055dba019.png

对应的值:

0209a43cad0579f101557cf757f4dfb5.png

第十二个常量:

fc6a871a65dd212d668c7d776c512976.png

对应的值:

93ae2061e97d9e4caaecd1ca29bf5629.png

第十三个常量:

1a789d56ffd7f5813aacd2b397421cbc.png

对应的值:

这里19转为10进制是25

12e28edb2c09a5846d27cec5c47d5782.png

第十四个常量:

1375e5ba198d54b9527e8f25c5b3d0f4.png

对应的值为:

2970019a470cfce4d4c7f5d6608985f1.png

第十五个常量:

b27f656903d9db773068c5db8fec142e.png

对应的值为:

9757f031d89865eb92accf432f41dfa2.png

第十六个常量:

96058ddc3ddeed5a7f9b985e35505b4d.png

对应的值为:

9ebc3474927f9c130921478583109c5a.png

第十七个常量:

d329e274ac17fc4771a65a10b37a413f.png

对应的值为:

1c2f8ee1a97c62318bdc603a6e974890.png

第十八个常量为:

fe6ed06999addb01fa9046638bf215f8.png

对应的值为:

ec9ab98a147d7bb817a0bcbcfb63ac89.png

第十九个常量为:

da86e8ea86720044e89085bab1969a0d.png

对应值为:

3bd1ec8a817924bf01ac7be8a2d7daf2.png

第二十个常量为:

e851d8bc00a0b5edba5cc9ca9919e14f.png

0C转为10进制为12

c60a8b9bfb3654ffd25e899f63754164.png

对应值:

d6fc146222466aa0f2887cc2c4f96cf4.png

第二十一个常量为:

38f865972d64b8216d134ffc7318d8ac.png

abbd6c7479d71d41749d189d64715569.png

9831e3b700b7119e708b91763add23fc.png

第二十二个常量为:

028e80926c110a043d200df6a7b9f8db.png

对应的值为:

c6bbaaddf5a53e1da9af4cb1f7b3b8f9.png

第二十三常量为:

941dd954b830562ec16f26cb0df7258f.png

对应的值为:

1be1390d00b7e60c57d104b069c02e76.png

第二十四常量为:

62a8ac45eb9925db38fa91cb442ee643.png

对应的值为:

2a1c2daa63ef9d92074300982ee79d8e.png

第二十五常量为:

a5e97fda13896ff8a4da0244a278256e.png

对应的值为:

8ab50abf902300da0daed86ea8b1a3f6.png

第二十六常量为:

b85346fa6d890d82416b7d3678271055.png

对应的值为:

2c06722bcc1b456fc55a28af144a2a3e.png

第二十七常量为:

15e745615c1afbb8b3c347a692fefc2d.png

对应的值为:

d04d9fc53c5d64b47d6011fed2a23714.png

第二十八个常量值为:

59039bbcd59fe97026d8134cbb02afd0.png

对应的值为:

6374a5724896560e6567d3bfdcd63cf0.png

第二十九个常量值为:

5b596c4004a83319caafb0eff1d08eb1.png

对应的值为:

824dbe91b702358c04f7033809655ad3.png

第三十个常量值为:

0a86e7ca5d62c3d72d18e1de84a18f4d.png

对应的值为:

8b5c595800825e11100cb8f4d4ba9c98.png

第三十一个常量值为:

88b4db78624e748ba7be3a92a289ecd5.png

对应的值为:

5f7e5b951759dbca848c79498fcf73b9.png

第三十二个常量值为:

4c7592ba8638588b7dcc4fbaf9f50a1a.png

对应的值为:

e207a7dbafb5408b5bd3a98fa7b29bc2.png

第三十三个常量:

594190dd2c3222f8b7692b618d33a3cb.png

对应的值为:

63dd10762756b5fa6172bce64e20ced0.png

接下来我们看到

e5ca77ab4ba364248327ac9cbe2a91f0.png

access_flags为 00 21

this_class为00 05

super_class为00 06

interfaces_count为00 00

通过执行javap -verbose Hello.class可以得到如下信息

Classfile /C:/JavaBase/out/production/HashMapTest/com/work/bytetest/Hello.classLast modified2020-12-16; size 548bytes

MD5 checksum b57a9425d15445dfb2a9a2dc0eb5fabe

Compiled from"Hello.java"

public classcom.work.bytetest.Hello

minor version:0major version:52flags: ACC_PUBLIC, ACC_SUPER

Constant pool:

#1 = Methodref #6.#20 //java/lang/Object."":()V

#2 = Fieldref #21.#22 //java/lang/System.out:Ljava/io/PrintStream;

#3 = String #23 //hello

#4 = Methodref #24.#25 //java/io/PrintStream.println:(Ljava/lang/String;)V

#5 = Class #26 //com/work/bytetest/Hello

#6 = Class #27 //java/lang/Object

#7 = Utf8 #8 =Utf8 ()V

#9 =Utf8 Code

#10 =Utf8 LineNumberTable

#11 =Utf8 LocalVariableTable

#12 = Utf8 this#13 = Utf8 Lcom/work/bytetest/Hello;

#14 =Utf8 main

#15 = Utf8 ([Ljava/lang/String;)V

#16 =Utf8 args

#17 = Utf8 [Ljava/lang/String;

#18 =Utf8 SourceFile

#19 =Utf8 Hello.java

#20 = NameAndType #7:#8 //"":()V

#21 = Class #28 //java/lang/System

#22 = NameAndType #29:#30 //out:Ljava/io/PrintStream;

#23 =Utf8 hello

#24 = Class #31 //java/io/PrintStream

#25 = NameAndType #32:#33 //println:(Ljava/lang/String;)V

#26 = Utf8 com/work/bytetest/Hello

#27 = Utf8 java/lang/Object

#28 = Utf8 java/lang/System

#29 =Utf8 out

#30 = Utf8 Ljava/io/PrintStream;

#31 = Utf8 java/io/PrintStream

#32 =Utf8 println

#33 = Utf8 (Ljava/lang/String;)V

{publiccom.work.bytetest.Hello();

descriptor: ()V

flags: ACC_PUBLIC

Code:

stack=1, locals=1, args_size=1

0: aload_01: invokespecial #1 //Method java/lang/Object."":()V

4: returnLineNumberTable:

line3: 0LocalVariableTable:

Start Length Slot Name Signature0 5 0 this Lcom/work/bytetest/Hello;public static voidmain(java.lang.String[]);

descriptor: ([Ljava/lang/String;)V

flags: ACC_PUBLIC, ACC_STATIC

Code:

stack=2, locals=1, args_size=1

0: getstatic #2 //Field java/lang/System.out:Ljava/io/PrintStream;

3: ldc #3 //String hello

5: invokevirtual #4 //Method java/io/PrintStream.println:(Ljava/lang/String;)V

8: returnLineNumberTable:

line5: 0line6: 8LocalVariableTable:

Start Length Slot Name Signature0 9 0 args [Ljava/lang/String;

}

SourceFile:"Hello.java"

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值