什么是class Class文件是一组以8个字节为基础单位的二进制流,各个数据项目严格按照顺序紧凑地排列在文件之中,中间没有添加任何分隔符,这使得整个Class文件中存储的内容几乎全部是程序运行的必要数据,没有空隙存在。当遇到需要占用8个字节以上空间的数据项时,则会按照高位在前的方式分割成若干个8个字节进行存储。 无符号数属于基本的数据类型,以u1、u2、u4、u8来分别代表1个字节、2个字节、4个字节和8个字节的无符号数,无符号数可以用来描述数字、索引引用、数量值或者按照UTF8编码构成字符串值。 表是由多个无符号数或者其他表作为数据项构成的复合数据类型,为了便于区分,所有表的命名都习惯性地以info结尾。表用于描述有层次关系的复合结构的数据,整个Class文件本质上也可以视作是一张表,这张表数据项按严格顺序排列构成。 接下来以个实际的class来分析类的字节码结构。先来看看一个简单的类publicclassJavapTest{privateintcount;publicintsum(intx){countx;returncount;}staticclassTest{Stringxtest;}} 通过javap可得到下面内容publicclasscom。zl。basic。JavapTestminorversion:0majorversion:52flags:ACCPUBLIC,ACCSUPERConstantpool:1Methodref4。18javalangObject。init:()V2Fieldref3。19comzlbasicJavapTest。count:I3Class20comzlbasicJavapTest4Class21javalangObject5Class22comzlbasicJavapTestTest6Utf8Test7Utf8InnerClasses8Utf8count9Utf8I10Utf8init11Utf8()V12Utf8Code13Utf8LineNumberTable14Utf8sum15Utf8(I)I16Utf8SourceFile17Utf8JavapTest。java18NameAndType10:11init:()V19NameAndType8:9count:I20Utf8comzlbasicJavapTest21Utf8javalangObject22Utf8comzlbasicJavapTestTest{publiccom。zl。basic。JavapTest();descriptor:()Vflags:ACCPUBLICCode:stack1,locals1,argssize10:aload01:invokespecial1MethodjavalangObject。init:()V4:returnLineNumberTable:line3:0publicintsum(int);descriptor:(I)Iflags:ACCPUBLICCode:stack3,locals2,argssize20:aload01:dup2:getfield2Fieldcount:I5:iload16:iadd7:putfield2Fieldcount:I10:aload011:getfield2Fieldcount:I14:ireturnLineNumberTable:line8:0line9:10}SourceFile:JavapTest。javaInnerClasses:static65of3;TestclasscomzlbasicJavapTestTestofclasscomzlbasicJavapTest 我们再来逐个字节分析一下,就知道上面内容是怎么来的。用HexEditorNeo打开JavapTest。class。 JavapTest。class 图中的红色数字代表一个项,作为代号我们来逐个分析一下。 1魔数确定这个文件是否为一个能被虚拟机接受的Class文件 2次版本号 3主版本号,34换算10进制为52 4常量池数量,0017换算为10进制为23,常量池计数从1开始,所以共有22个常量 5第一项常量访问标志0a,代表方法引用,0004(4),0012(18)分别指向第4,18个常量 6第二项常量访问标志09代表字段引用,0003(3),0013(19)分别指向第3,19个常量 7第三个常量访问标志07代表类的全限定名0014(20)指向第20个常量 8第四个常量访问标志07代表类的全限定名0014(21)指向第21个常量 9第五个常量访问标志07代表类的全限定名0014(22)指向第22个常量 10第6个常量访问标志01为utf8字符,0004代表有4个字节Test 11第7个常量访问标志01为utf8字符,000c代表后面12个字节是该常量的值InnerClasses 12第8个常量访问标志01为utf8字符,0005代表后面5个字节是该常量的值count 13第9个常量访问标志01为utf8字符,0001代表后面1个字节是该常量的值I 14第10个常量访问标志01为utf8字符,0006代表后面6个字节是该常量的值 15第11个常量访问标志01为utf8字符,0003代表后面3个字节是该常量的值()V 16第12个常量访问标志01为utf8字符,0004代表后面4个字节是该常量的值Code 17第13个常量访问标志01为utf8字符,000f代表后面15个字节是该常量的值LineNumberTable 18第14个常量访问标志01为utf8字符,0003代表后面3个字节是该常量的值sum 19第15个常量访问标志01为utf8字符,0004代表后面4个字节是该常量的值(I)I 20第16个常量访问标志01为utf8字符,000a代表后面10个字节是该常量的值SourceFile 21第17个常量访问标志01为utf8字符,000e代表后面14个字节是该常量的值JavapTest。java 22第18个常量访问标志0c为NameAndType常量,000a(10),000b(11)分别执行第10和11个常量 23第19个常量访问标志01为NameAndType常量,000a(8),000b(9)分别执行第8和9个常量 24第20个常量访问标志01为utf8字符,0016代表后面22个字节是该常量的值comzlbasicJavapTest 25第21个常量访问标志01为utf8字符,0010代表后面16个字节是该常量的值javalangObject 26第22个常量访问标志01为utf8字符,001b代表后面22个字节是该常量的值comzlbasicJavapTestTest 27访问标志0021ACCPUBLIC、ACCSUPER标志为真000100200021 28类索引0003指向第三个常量 29父类索引0004指向第四个常量 30接口索引0000代表没有实现接口 310001代表字段数量1,0002代表private,0008代表字段名称指向常量池的I表示int,0009代表字段描述符指向常量池9即count 方法访问标志说明 320002代表有两个方法,0001代表public,000a指向第十个常量,000b指向第11个常量,0001代表有一个属性,属性名称的索引值为0x000c,对应常量为Code,说明此属性是方法的字节码描述,0000001d(29)代表代码长度,0001是maxstack操作数栈最大深度,0001局部变量表所占的Slot,接下来的四个字节(00000005)是代码长度,字节码长度为5,接下来的5个字节2AB70001B1,接下来0000两个自己表示式异常处理表,这里没有异常所以是0,接着0001属性表示有一个属性,属性索引为000d(13)在常量池中的引用是LineNumberTable。00000006是属性长度,表示后面6字节是它的长度。0001是行号表长度1,包含startpc和linenumber两个u2类型的数据项,前者是字节码行号,后者是Java源码行号(0000:字节码行号,0003:java源码行号) 33。是第二个方法,0001代表public,000e指向第11个常量,000f指向第15个常量,0001代表有一个属性,属性名称的索引值为0x000c,对应常量为Code,0000002b(43)是代码长度,0003,0002分别是栈深度和局部变量表。0000000f(15)字节码长度,2a59b400021b60b500022ab40002ac,0000yi异常处理表,0001有一个属性,000d(13)LineNumberTable,0000000a(10)属性长度,000200000008000a0009(0002行长度为2,0000:0008字节码和源码行号,第二个000a:0009), 方法属性完了继续是内的属性,接下来的0002表示有量个类属性。0010表示指向16号常量SourceFile,00000002是属性长度,0011指向17号常量即JavapTest。java, 0007指向第7个常量池InnerClasses,0000000a(10)属性长度,0001表示内部类数量为1。 0005内部内索引5,0003外部类索引3,内部类名索引指向第6个常量池,0008内部内访问标志是静态标志 至此,JavapTest类的每个字节都分析清楚了,工作中可能用不到这些,但是作为程序员的你一定要知道这个class是怎么组织的很重要。深入理解java是必不可少的。