分析一个Java Class文件
发布时间:2020-12-13 20:43:57 所属栏目:PHP教程 来源:网络整理
导读:Java源码文件TestClass.java: package jvm.chapter6;//P166public class TestClass {private int m;public int inc(){return m+1;}} 展现这个Class文件的16进制内容: 从头开始分析= ca fe ba be :magic number; 00 00 00 34 : 版本号是1.8.0; 00 16: 说明
Java源码文件TestClass.java: package jvm.chapter6;
//P166
public class TestClass {
private int m;
public int inc(){
return m+1;
}
} 展现这个Class文件的16进制内容:
从头开始分析=> ca fe ba be :magic number; 00 00 00 34 : 版本号是1.8.0; 00 16: 说明常量池有21个常量,1⑵1, index留做他用;接下来就是分别这21个常量的描写: 07/00 02 :CONSTANT_Class_info 常量,类名索引是该常量池的第2项; 01/00 16/6a 76 6d 2f 63 68 61 70 74 65 72 36 2f 54 65 73 74 43 6c 61 73 73 :这是该常量池的第2项,CONSTANT_Utf8_info常量,长度是22(0x0016),正是字符串常量“jvm/chapter6/TestClass”; 07/00 04:CONSTANT_Class_info 常量,类名索引是该常量池的第4项; 01/00 10/6a 61 76 61 2f 6c 61 6e 67 2f 4f 62 6a 65 63 74:这是该常量池的第4项,CONSTANT_Utf8_info常量,长度是16(0x0010),正是字符串常量“java/lang/Object”; 01/00 01/6d :CONSTANT_Utf8_info常量,是字符串常量"m"; 01/00 01/49 :CONSTANT_Utf8_info常量,是字符串常量"m"; 01/00 06/3c 69 6e 69 74 3e :CONSTANT_Utf8_info常量,是字符串常量"<init>"; 01/00 03/28 29 56 :CONSTANT_Utf8_info常量,是字符串常量"()V"; 01/00 04/43 6f 64 65 :CONSTANT_Utf8_info常量,是字符串常量"Code"; 0a/00 03/00 0b: tag=10,表示CONSTANT_Methodref_info常量,声明该方法的类名称位于常量池的第3项,即java/lang/Object,方法名和类型NameAndType="<init>":()V; 0c/00 07/00 08: 接下来tag=12就是上面刚说道的CONSTANT_NameAndType_info类型,接下来的两个索引分别指向方法名和描写符即"<init>"和“()V”, 01/00 0f/4c 69 6e 65 4e 75 6d 62 65 72 54 61 62 6c 65 :CONSTANT_Utf8_info常量,是字符串常量"LineNumberTable"; 01/00 12/4c 6f 63 61 6c 56 61 72 69 61 62 6c 65 54 61 62 6c 65 :CONSTANT_Utf8_info常量,是字符串常量"LocalVariableTable"; 01/00 04/74 68 69 73 :CONSTANT_Utf8_info常量,是字符串常量"this"; 01/00 18/4c 6a 76 6d 2f 63 68 61 70 74 65 72 36 2f 54 65 73 74 43 6c 61 73 73 3b:CONSTANT_Utf8_info常量,是字符串常量"Ljvm/chapter6/TestClass;"; 01/00 03 69 6e 63 :CONSTANT_Utf8_info常量,是字符串常量"inc"; 01/00 03 28 29 49 :CONSTANT_Utf8_info常量,是字符串常量"()I"; 09/00 01/00 13:代表Fieldref常量,然后接下来两个u2分别表示声明该字段的类和NameAndType的索引; 0c/00 05/00 06:就是上面刚使用的NameAndType常量; 01/00 0a/53 6f 75 72 63 65 46 69 6c 65 :CONSTANT_Utf8_info常量,是字符串常量"SourceFile"; 01 00 0e 54 65 73 74 43 6c 61 73 73 2e 6a 61 76 61::CONSTANT_Utf8_info常量,是字符串常量"TestClass.java"; 上面就分析完了常量池中的字段, 00 21 : access_flags= ACC_PUBLIC | ACC_SUPER = 0x0021; 00 01 00 03 00 00:类索引 父类索引 和接口索引,常量池第3项表示的是Object,说明了默许的父类就是Object,没有实现接口,所以interfaces_count=0; 00 01/00 02/00 05/00 06/00 00: 接下来的是字段表集合(fields_info),fields_count=1,access_flags=0x0002=ACC_PRIVATE,代表字段名称的name_index=5(常量池的第5项是CONSTANT_Utf8_info类型的字符串m),字段描写符descriptor_index=0x0006(常量池的第5项是CONSTANT_Utf8_info类型的字符串I),最后atributes_count=0,说明不包括额外的信息。总上这些信息正是为了说明定义的字段“private int m”; 00 02/00 01/00 07/00 08/00 01/00 09/00 00 00 2f/00 01/00 01/00 00 00 05/2a b7 00 0a b1:接下来的是方法集合(methods_info),有两个方法,第1个方法的访问标志是0x0001=ACC_PUBLIC,名称索引是0x0007,指向常量池中的<init>,描写符索引值是0x0008,指向常量池中的"()V",接下来属性表计数器attributes_count=1,属性名称索引是0x0009对应的是“Code”,接下来就是Code属性表的结构:属性值的长度attribute_length=0x2f;操作数栈的最大深度和本地变量表的容量都是0x0001;字节码指令长度是5,翻译“2a b7 00 0a b1”的进程是: 1)读入2a,对应的是aload_0 ,将第1个援用类型的本地变量推送到操作数栈顶; 2)读入b7,对应的是invokespecial,作用是调用以栈顶的reference类型所指向的对象的构造器方法 实例初始化方法 私有方法,接下来有1个u2类型的参数说明具体调用哪一个方法,它指向常量池中1个CONSTANT_Methodref_info的常量,即那个方法的符号援用; 3)00 0a正是上面invokespecial的参数,指向常量池中的1个Methodref常量,对应的应当是Object.init()方法; 4)b1,对应的指令是return,并且返回类型是oid,当前方法对应的指令结束。 继续上面的分析, 00 00/00 02/00 0c/00 00 00 06/00 01/00 00/00 03|00 0d/00 00 00 0c/00 01|00 00/00 05/00 0e/00 0f/00 00:exception_table_length=0,该方法没有抛出异常,然后attributes_count=2,该Code属性有俩属性:0x000c指向常量池中的“LineNumberTable”,attribute_length=6,line_number_table_length=1,就是记录了1对java源码行号和字节码行号的对应关系(3:0);0x000d指向常量池中的“LocalVariableTable”,attribute_length=12,local_variable_table_length=1(代表了1个栈帧和程序中的局部变量关联关系),start_pc=0x0000,length=0x0005表征该局部变量在字节码中的作用范围(就是这个方法内),name_index=0x000e,descriptor_index=0x000f表示该局部变量的名称及其描写符,即为“this”,"Ljvm/chapter6/TestClass";通过javap的输出都可以1目了然。index=0x0000代表该局部变量在栈帧局部变量表中Slot的位置。 接下来看第2个方法, 00 01/00 10/00 11/00 01/00 09/00 00 00 31/00 02/00 01/00 00 00 07/2a b4 00 12 04 60 ac/:方法的访问标志是0x0001=ACC_PUBLIC,名称索引是16,指向常量池中的“inc”,描写符索引值是0x0011,指向常量池中的"()I",接下来属性表计数器attributes_count=1,属性名称索引是0x0009对应的是“Code”,接下来就是Code属性表的结构:属性值的长度attribute_length=0x31;操作数栈的最大深度是2,本地变量表的容量是1;字节码指令长度是7,翻译“2a b4 00 12 04 60 ac”的进程是: 1)读入2a,对应的是aload_0 ,将第1个援用类型的本地变量推送到操作数栈顶; 2)读入b4,对应的指令是getfield,取得实例域,并压入栈顶,他需要参数用来讲明把哪一个变量入栈,即下面; 3)读入00 12,用来指明getfield 哪一个字段,指向常量池中的1个Fieldref常量,“jvm/chapter6/TestClass.m:I”; 4)读入04,对应的指令是iconst_1,将int类型的1推至栈顶; 5)读入60,对应的指令是iadd,将栈顶两个int类型的数值相加并把结果压入栈顶; 6)读入ac,对应的指令是ireturn,从当前方法返回int,结束。 后面的俩属性就和分析第1个方法类似。 至此,就分析完了1个简单的Class文件的结构,清晰了很多。 附: Javap TestClass.class的结果:$ javap -verbose TestClass.class Classfile /home/vonzhou/GitHub/JavaProject/learning-java/bin/jvm/chapter6/TestClass.classLast modified Apr 29,2015; size 379 bytes MD5 checksum 70a67e773b621619d03f9d1b5ac91af6 Compiled from "TestClass.java" public class jvm.chapter6.TestClass SourceFile: "TestClass.java" minor version: 0 major version: 52 flags: ACC_PUBLIC,ACC_SUPER Constant pool: #1 = Class #2; // jvm/chapter6/TestClass #2 = Utf8 jvm/chapter6/TestClass; #3 = Class #4; // java/lang/Object #4 = Utf8 java/lang/Object; #5 = Utf8 m; #6 = Utf8 I; #7 = Utf8 <init>; #8 = Utf8 ()V; #9 = Utf8 Code; #10 = Methodref #3.#11; // java/lang/Object."<init>":()V #11 = NameAndType #7:#8; // "<init>":()V #12 = Utf8 LineNumberTable; #13 = Utf8 LocalVariableTable; #14 = Utf8 this; #15 = Utf8 Ljvm/chapter6/TestClass;; #16 = Utf8 inc; #17 = Utf8 ()I; #18 = Fieldref #1.#19; // jvm/chapter6/TestClass.m:I #19 = NameAndType #5:#6; // m:I #20 = Utf8 SourceFile; #21 = Utf8 TestClass.java; { public jvm.chapter6.TestClass(); flags: ACC_PUBLIC Code: stack=1,locals=1,args_size=1 0: aload_0 1: invokespecial #10; // Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 3: 0 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Ljvm/chapter6/TestClass; public int inc(); flags: ACC_PUBLIC Code: stack=2,args_size=1 0: aload_0 1: getfield #18; // Field m:I 4: iconst_1 5: iadd 6: ireturn LineNumberTable: line 6: 0 LocalVariableTable: Start Length Slot Name Signature 0 7 0 this Ljvm/chapter6/TestClass; } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
相关内容
- php从数据库中获取数据用ajax传送到前台的方法
- Yii – FullCalendar – 如何设置TimeZone?
- 如何在带有registerPHPFunctions的XSLT中使用DOMDocumentFr
- php – 错误消息“正在进行中的操作”是什么意思?
- php – 在array_unique函数作为JSON响应中的对象返回后的数
- PHP实现的最大正向匹配算法示例
- yii2 gridview没有使用hasMany retionship显示所有左连接值
- PHP中通过HTTP_USER_AGENT判断是否为手机移动终端的函数代码
- 如何在php中只读文本框
- Smarty实现页面静态化(生成HTML)的方法