HelloWorld.class 文件的解读---方法解读
前面两个例子,一个简单的替换了二进制的编码,一个通过理解class的文件格式,可以增加输出的内容,都非常简单,但是实际可能用到的不会这么简单,更多的是对方法的操作,比如spring aop的实现方式有两种动态代理和字节码增强,其中字节码增强便可以通过修改class的二进制文件完成,另外对性能分析、调试跟踪和日志记录,也可以通过这种方式简单的实现,当然在现实中我们不会去真正的操作二进制码,我们一般通过第三方的库文件,比如:asm、 cglib、 serp、 和bcel等;但是他们的本质还是去操作二进制码;前面在分析helloworld.class 的时候,还剩下两块内容当时没有讨论(其实是一样的结构),这里我们先讨论这两块内容:
第一块: 第39点后面剩下的29个字节如下(请先回顾39点的内容):
?
?
0000014fh: 00 01 00 01 00 00 00 05 2A B7 00 01 B1 00 00 00 ; ........*?.?..0000015fh: 01 00 0A 00 00 00 06 00 01 00 00 00 01 ; .............
?Code_attribute 的定义:
?
?
?
Code_attribute { u2 attribute_name_index; u4 attribute_length; u2 max_stack; u2 max_locals; u4 code_length; u1 code[code_length]; u2 exception_table_length; { u2 start_pc; u2 end_pc; u2 handler_pc; u2 catch_type; } exception_table[exception_table_length]; u2 attributes_count; attribute_info attributes[attributes_count]; } ??
?按照Code_attribute 的定义分析29个字符:
(1)、0X 00 01 表示max_stack;表示该方法执行的时候操作数栈最大的长度;这里表示操作数栈的长度为1;
(2)、0X 00 01表示?max_locals;表示方法局部变量所需要的空间的长度,
(3)、0X 00 00 00 05 表示code_length=5;即后面的5个字节为code的内容;
(4)、0X?2A B7 00 01 B1 :5个字节表示的便是code 的内容;
?
?
0X 2A :aload_0 表示将第一个引用类型本地变量推送至栈顶 ?0X B7 :invokespecial???调用超类方法,后面的0X 00 01,查看1号常量池 表示void?init();所有表示调用超类的init方法0X B1 return 返回void;(5)、0X 00 00 :表示exception_table_length=0;也就是说没有异常处理;
(6)、0X 00 01 :表示attributes_count=1;接下来有一个attribute_info 的结构:
?
先复习一下attribute_info 的结构定义:
?
?
attribute_info { u2 attribute_name_index; u4 attribute_length; u1 info[attribute_length]; }?
? ? ?1)、0X 00 0A :表示 ?attribute_name_index,查看10号常量池,为LineNumberTable ;查看LineNumberTable ?属性的定义:
?
?
lineNumberTable_attribute{U2 attribute_name_index;U4 attribute_length;U2 line_number_table_lengthline_number_info line_number_table }line_number_info 的定义:line_number_info {U2 start_pc;U2 line_number;}?
? ?2)、0X 00 00 00 06 :表示attribute_length=6,
? ?3)、0X 00 01 :表示line_number_table_length=1,即后面有一个line_number_info 结构
? ? ? ?3.1)、0X 00 00 表示 start_pc; 新行开始时,代码数组的偏移量,该偏移量从代码数组的起始位置开始;
? ? ? ?3.2)、0X 00 01 表示 line_number=1
?
LineNumberTable ?中包含了一些调试信息,不做讨论;
到这里第一块结构就ok了;
?
第二块: 第41点后面剩下的37个字节如下(请先回顾41点的内容):这个结构和上面的第一块内容基本一致;
?
0000017ah: 00 02 00 01 00 00 00 09 B2 00 02 12 03 B6 00 04 ; ........?...?.0000018ah: B1 00 00 00 01 00 0A 00 00 00 0A 00 02 00 00 00 ; ?..............0000019ah: 03 00 08 00 04 ; .....?
?
(1)、0X 00 02 表示max_stack;表示该方法执行的时候操作数栈最大的长度;这里表示操作数栈的长度为2;
(2)、0X 00 01 表示?max_locals;表示方法局部变量所需要的空间的长度
(3)、0X 00 00 00 09 表示code_length=5;即后面的9个字节为code的内容;
(4)、 B2 00 02 12 03 B6 00 04?B1 :9个字节表示的便是code 的内容;
? ? ? 该code[] 包含的实现该方法的JVM 的实际的字节,
?
0X B2 :getstatic 指令:表示获取指定类的静态域,并将其值压入栈顶,后面的0X 00 02 ;查看2号常量池,即将out(sysytem.out)压入栈0X 12 :ldc:表示将一个常量池压入操作栈,后面的0X 03 便是这个操作数,查看第3号常量池,为hello world,我们要输出的内容;0X B6 : invokevirtual,调用实例方法,后面的0X 00 04 ,查看4号常量池 表示java/io/PrintStream的println方法,这个指令弹出两个操作数,即是调用 out.print("hello world");0X?B1 : return ;返回void?
(5)、0X 00 00 :表示exception_table_length=0;也就是说没有异常处理;
(6)、0X 00 01 :表示attributes_count=1;接下来有一个attribute_info 的结构:
? ?1)、0X 00 0A :表示 ?attribute_name_index,查看10号常量池,为LineNumberTable ;
? ? ? ? ? ? ?查 看LineNumberTable ?属性的定义:
?
? ?2)、0X 00 00 00 0A :表示attribute_length=10,
? ?3)、0X 00 02 :表示line_number_table_length=2,即后面有一个line_number_info 结构
? ? ? ?3.1)、0X 00 00 表示 start_pc;新行开始时,代码数组的偏移量,该偏移量从代码数组的起始位置开始;
? ? ? ?3.2)、0X 00 03 表示 line_number=3
?
? ? ? ?3.3)、0X 00 08 表示 start_pc;新行开始时,代码数组的偏移量,该偏移量从代码数组的起始位置开始;
? ? ? ?3.4)、0X 00 04 表示 line_number=4
LineNumberTable ?中包含了一些调试信息,不做讨论;
至此 整个helloworld的class 文件全部分析好了,
另外:
1、文章中提高的指令集参照?http://thinkinmylife.iteye.com/blog/443900
2、对在class 复合数据结构中的 9中属性没有做详细的介绍,只是对用到的code_attribute,sourcefile_attribute,linenumbertable_attribute ,有一个简单的说明,其他还有sythetic、localvariabletable、innerclass、exception、deprecated、constantvalue几种;
?
1 楼 TheNewBeginning 2011-07-10 虽然还不理解,先支持下。 2 楼 诸葛不亮 2011-07-11 TheNewBeginning 写道虽然还不理解,先支持下。说明这个表达能力亟待提高啊。。哈哈! 3 楼 xm_king 2011-07-11 楼主很耐心,很认真,很有钻研精神。很有做黑客的潜质 4 楼 xm_king 2011-07-11 Spring 实现AOP的两种方式的第一种动态代理看过Spring的源码,基本明白了。字节码增强没看过,两种方式比较的话,显然是字节码增强技术的效率更高。 5 楼 xm_king 2011-07-11 希望楼主加油